diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d357713bff..6207ecdb3c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -387,21 +387,9 @@ Menu::Menu() { }); #ifdef Q_OS_WIN - #define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5 - bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); - bool recommendedSparseTextures = recommendedIncrementalTransfers; - - qDebug() << "[TEXTURE TRANSFER SUPPORT]" - << "\n\tidealThreadCount:" << QThread::idealThreadCount() - << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures - << "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers; - - gpu::Texture::setEnableIncrementalTextureTransfers(recommendedIncrementalTransfers); - gpu::Texture::setEnableSparseTextures(recommendedSparseTextures); - - // Developer > Render > Enable Dynamic Texture Management + // Developer > Render > Enable Sparse Textures { - auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableDynamicTextureManagement, 0, recommendedSparseTextures); + auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::SparseTextureManagement, 0, gpu::Texture::getEnableSparseTextures()); connect(action, &QAction::triggered, [&](bool checked) { qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Dynamic Texture Management menu option:" << checked; gpu::Texture::setEnableSparseTextures(checked); @@ -410,7 +398,7 @@ Menu::Menu() { // Developer > Render > Enable Incremental Texture Transfer { - auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableIncrementalTextureTransfer, 0, recommendedIncrementalTransfers); + auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::IncrementalTextureTransfer, 0, gpu::Texture::getEnableIncrementalTextureTransfers()); connect(action, &QAction::triggered, [&](bool checked) { qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Incremental Texture Transfer menu option:" << checked; gpu::Texture::setEnableIncrementalTextureTransfers(checked); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 640a3e05d2..87e0e678f1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -97,8 +97,6 @@ namespace MenuOption { const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString EnableCharacterController = "Enable avatar collisions"; - const QString EnableIncrementalTextureTransfer = "Enable Incremental Texture Transfer"; - const QString EnableDynamicTextureManagement = "Enable Dynamic Texture Management"; const QString EnableInverseKinematics = "Enable Inverse Kinematics"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; @@ -114,6 +112,7 @@ namespace MenuOption { const QString FrameTimer = "Show Timer"; const QString FullscreenMirror = "Mirror"; const QString Help = "Help..."; + const QString IncrementalTextureTransfer = "Enable Incremental Texture Transfer"; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IndependentMode = "Independent Mode"; const QString ActionMotorControl = "Enable Default Motor Control"; @@ -180,6 +179,7 @@ namespace MenuOption { const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; const QString SimulateEyeTracking = "Simulate"; const QString SMIEyeTracking = "SMI Eye Tracking"; + const QString SparseTextureManagement = "Enable Sparse Texture Management"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 1be279b375..417b090d31 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -177,7 +177,6 @@ public: virtual void queueLambda(const std::function lambda) const; bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); } - bool isTextureManagementIncrementalTransferEnabled() const override { return (_textureManagement._incrementalTransferCapable && Texture::getEnableIncrementalTextureTransfers()); } protected: @@ -369,7 +368,6 @@ protected: struct TextureManagementStageState { bool _sparseCapable { false }; - bool _incrementalTransferCapable { false }; } _textureManagement; virtual void initTextureManagementStage() {} diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 3ce1c8e5c4..1e0dd08ae1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -116,7 +116,7 @@ float GLTexture::getMemoryPressure() { } // Return the consumed texture memory divided by the available texture memory. - auto consumedGpuMemory = Context::getTextureGPUSparseMemoryUsage(); + auto consumedGpuMemory = Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage(); float memoryPressure = (float)consumedGpuMemory / (float)availableTextureMemory; static Context::Size lastConsumedGpuMemory = 0; if (memoryPressure > 1.0f && lastConsumedGpuMemory != consumedGpuMemory) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 643d54af6a..438b1e9454 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -94,6 +94,7 @@ public: TransferState _transferState; uint32_t _allocatedPages { 0 }; uint32_t _lastMipAllocatedPages { 0 }; + uint16_t _mipOffset { 0 }; friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index ac9a84513e..f97364f5c5 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -148,13 +148,9 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { return pageCounts.x * pageCounts.y * pageCounts.z; } - - void GL45Backend::initTextureManagementStage() { - // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; - _textureManagement._incrementalTransferCapable = true; // But now let s refine the behavior based on vendor std::string vendor { (const char*)glGetString(GL_VENDOR) }; @@ -282,20 +278,22 @@ GL45Texture::~GL45Texture() { if (!_gpuObject.getUsage().isExternal()) { qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str(); } - if (_sparseInfo.sparse) { - Backend::decrementTextureGPUSparseCount(); - // 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); - } + + // Remove this texture from the candidate list of derezzable textures + if (_transferrable) { + 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) { + Backend::decrementTextureGPUSparseCount(); // 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 @@ -355,7 +353,7 @@ void GL45Texture::allocateStorage() const { 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); + Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip + _mipOffset); glTextureStorage2D(_id, usedMipLevels(), _internalFormat, dimensions.x, dimensions.y); (void)CHECK_GL_ERROR(); } @@ -370,7 +368,7 @@ void GL45Texture::updateSize() const { Backend::updateTextureGPUSparseMemoryUsage(_size, size); setSize(_allocatedPages * _sparseInfo.pageBytes); } else { - setSize(_virtualSize); + setSize(_gpuObject.evalTotalSize(_mipOffset)); } } @@ -381,15 +379,18 @@ void GL45Texture::startTransfer() { } bool GL45Texture::continueTransfer() { - auto backend = _backend.lock(); - if (!backend || !backend->isTextureManagementIncrementalTransferEnabled()) { + if (!Texture::getEnableIncrementalTextureTransfers()) { size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { + auto size = _gpuObject.evalMipDimensions(mipLevel); + if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { + glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); + _allocatedPages += _sparseInfo.getPageCount(size); + } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); - auto size = _gpuObject.evalMipDimensions(mipLevel); if (GL_TEXTURE_2D == _target) { glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); } else if (GL_TEXTURE_CUBE_MAP == _target) { @@ -481,35 +482,30 @@ void 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()); + // FIXME account for mip offsets here 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_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip() - _mipOffset)); glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); } void GL45Texture::postTransfer() { Parent::postTransfer(); - if (_sparseInfo.sparse) { - auto mipLevels = usedMipLevels(); - if (mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { - Lock lock(texturesByMipCountsMutex); - texturesByMipCounts[mipLevels].insert(this); - } + auto mipLevels = usedMipLevels(); + if (_transferrable && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { + Lock lock(texturesByMipCountsMutex); + texturesByMipCounts[mipLevels].insert(this); } } void GL45Texture::stripToMip(uint16_t newMinMip) { - if (!_sparseInfo.sparse) { - return; - } - if (newMinMip < _minMip) { qCWarning(gpugl45logging) << "Cannot decrease the min mip"; return; } - if (newMinMip > _sparseInfo.maxSparseLevel) { + if (_sparseInfo.sparse && newMinMip > _sparseInfo.maxSparseLevel) { qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail"; return; } @@ -533,19 +529,53 @@ 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); - _textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] { - glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); - }); + if (_sparseInfo.sparse) { + for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { + auto id = _id; + auto mipDimensions = _gpuObject.evalMipDimensions(mip); + _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; + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; + assert(deallocatedPages < _allocatedPages); + _allocatedPages -= deallocatedPages; + } + _minMip = newMinMip; + } else { + GLuint oldId = _id; + // Find the distance between the old min mip and the new one + uint16 mipDelta = newMinMip - _minMip; + _mipOffset += mipDelta; + const_cast(_maxMip) -= mipDelta; + auto newLevels = usedMipLevels(); + + // Create and setup the new texture (allocate) + glCreateTextures(_target, 1, &const_cast(_id)); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + Vec3u newDimensions = _gpuObject.evalMipDimensions(_mipOffset); + glTextureStorage2D(_id, newLevels, _internalFormat, newDimensions.x, newDimensions.y); + + // Copy the contents of the old texture to the new + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); + (void)CHECK_GL_ERROR(); + } + } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &oldId); } - _minMip = newMinMip; // Re-sync the sampler to force access to the new mip level syncSampler(); updateSize(); @@ -553,7 +583,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); - if (_sparseInfo.sparse && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { + if (mipLevels > 1 && (!_sparseInfo.sparse || _minMip < _sparseInfo.maxSparseLevel)) { Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } @@ -570,8 +600,9 @@ void GL45Texture::updateMips() { } void GL45Texture::derez() { - assert(_sparseInfo.sparse); - assert(_minMip < _sparseInfo.maxSparseLevel); + if (_sparseInfo.sparse) { + assert(_minMip < _sparseInfo.maxSparseLevel); + } assert(_minMip < _maxMip); assert(_transferrable); stripToMip(_minMip + 1); @@ -595,7 +626,7 @@ void GL45Backend::derezTextures() const { } qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); - qCDebug(gpugl45logging) << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); GL45Texture* targetTexture = nullptr; { @@ -605,5 +636,5 @@ void GL45Backend::derezTextures() const { } lock.unlock(); targetTexture->derez(); - qCDebug(gpugl45logging) << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "New Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 3564655a3d..19d2ae767f 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -86,7 +86,6 @@ public: void getStats(ContextStats& stats) const { stats = _stats; } virtual bool isTextureManagementSparseEnabled() const = 0; - virtual bool isTextureManagementIncrementalTransferEnabled() const = 0; // These should only be accessed by Backend implementation to repport the buffer and texture allocations, // they are NOT public calls diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 3283f5a4d9..33786155db 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -10,11 +10,13 @@ // -#include - #include "Texture.h" #include +#include + +#include +#include #include @@ -31,16 +33,27 @@ std::atomic Texture::_textureCPUCount{ 0 }; std::atomic Texture::_textureCPUMemoryUsage{ 0 }; std::atomic Texture::_allowedCPUMemoryUsage { 0 }; -std::atomic Texture::_enableSparseTextures { false }; -std::atomic Texture::_enableIncrementalTextureTransfers { false }; + +#define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5 +bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); +bool recommendedSparseTextures = recommendedIncrementalTransfers; + +std::atomic Texture::_enableSparseTextures { recommendedIncrementalTransfers }; +std::atomic Texture::_enableIncrementalTextureTransfers { recommendedSparseTextures }; + +struct ReportTextureState { + ReportTextureState() { + qDebug() << "[TEXTURE TRANSFER SUPPORT]" + << "\n\tidealThreadCount:" << QThread::idealThreadCount() + << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures + << "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers; + } +} report; void Texture::setEnableSparseTextures(bool enabled) { #ifdef Q_OS_WIN qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Sparse Textures and Dynamic Texture Management:" << enabled; _enableSparseTextures = enabled; - if (!_enableIncrementalTextureTransfers && _enableSparseTextures) { - qDebug() << "[TEXTURE TRANSFER SUPPORT] WARNING - Sparse texture management requires incremental texture transfer enabled."; - } #else qDebug() << "[TEXTURE TRANSFER SUPPORT] Sparse Textures and Dynamic Texture Management not supported on this platform."; #endif @@ -50,9 +63,6 @@ void Texture::setEnableIncrementalTextureTransfers(bool enabled) { #ifdef Q_OS_WIN qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Incremental Texture Transfer:" << enabled; _enableIncrementalTextureTransfers = enabled; - if (!_enableIncrementalTextureTransfers && _enableSparseTextures) { - qDebug() << "[TEXTURE TRANSFER SUPPORT] WARNING - Sparse texture management requires incremental texture transfer enabled."; - } #else qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer not supported on this platform."; #endif @@ -418,12 +428,18 @@ uint16 Texture::evalDimNumMips(uint16 size) { return 1 + (uint16) val; } +static const double LOG_2 = log(2.0); + +uint16 Texture::evalNumMips(const Vec3u& dimensions) { + double largerDim = glm::compMax(dimensions); + double val = log(largerDim) / LOG_2; + return 1 + (uint16)val; +} + // The number mips that the texture could have if all existed // = log2(max(width, height, depth)) uint16 Texture::evalNumMips() const { - double largerDim = std::max(std::max(_width, _height), _depth); - double val = log(largerDim)/log(2.0); - return 1 + (uint16) val; + return evalNumMips({ _width, _height, _depth }); } bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1eacb46d77..2a93ec3066 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -369,9 +369,12 @@ public: // = 1 + log2(max(width, height, depth)) uint16 evalNumMips() const; + static uint16 evalNumMips(const Vec3u& dimensions); + // Eval the size that the mips level SHOULD have // not the one stored in the Texture static const uint MIN_DIMENSION = 1; + Vec3u evalMipDimensions(uint16 level) const; uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); } uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); } @@ -388,9 +391,9 @@ public: uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); } uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); } - uint32 evalTotalSize() const { + uint32 evalTotalSize(uint16 startingMip = 0) const { uint32 size = 0; - uint16 minMipLevel = minMip(); + uint16 minMipLevel = std::max(minMip(), startingMip); uint16 maxMipLevel = maxMip(); for (uint16 l = minMipLevel; l <= maxMipLevel; l++) { size += evalMipSize(l); diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index d4a8322f8a..b152c4b4bf 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -599,7 +599,7 @@ protected: return; case Qt::Key_End: - gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(256)); + gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(64)); return;