From 8615ec5596d69cae9c0d13e56c5dfad497f88dbb Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Thu, 6 Aug 2020 22:58:17 +0200 Subject: [PATCH 1/7] Initial version of automatic texture memory size --- libraries/gl/src/gl/Config.cpp | 19 +++++ libraries/gl/src/gl/Config.h | 1 + .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 85 +++++++++++++++++-- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 24 ++++++ .../src/gpu/gl/GLTextureTransfer.cpp | 6 +- 5 files changed, 129 insertions(+), 6 deletions(-) diff --git a/libraries/gl/src/gl/Config.cpp b/libraries/gl/src/gl/Config.cpp index 94bb91a3e9..759cbb98a8 100644 --- a/libraries/gl/src/gl/Config.cpp +++ b/libraries/gl/src/gl/Config.cpp @@ -74,6 +74,10 @@ static void* getGlProcessAddress(const char *namez) { #else + +typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); +PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC QueryCurrentRendererIntegerMESA; + static void* getGlProcessAddress(const char *namez) { return (void*)glXGetProcAddressARB((const GLubyte*)namez); } @@ -92,6 +96,10 @@ void gl::initModuleGl() { wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)getGlProcessAddress("wglCreateContextAttribsARB"); #endif +#if defined(Q_OS_LINUX) + QueryCurrentRendererIntegerMESA = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)getGlProcessAddress("glXQueryCurrentRendererIntegerMESA"); +#endif + #if defined(USE_GLES) gladLoadGLES2Loader(getGlProcessAddress); #else @@ -124,3 +132,14 @@ void gl::setSwapInterval(int interval) { Q_UNUSED(interval); #endif } + +bool gl::queryCurrentRendererIntegerMESA(int attr, unsigned int *value) { + #if defined(Q_OS_LINUX) + if (QueryCurrentRendererIntegerMESA) { + return QueryCurrentRendererIntegerMESA(attr, value); + } + #endif + + *value = 0; + return false; +} diff --git a/libraries/gl/src/gl/Config.h b/libraries/gl/src/gl/Config.h index aad000a242..8defbc5bca 100644 --- a/libraries/gl/src/gl/Config.h +++ b/libraries/gl/src/gl/Config.h @@ -52,6 +52,7 @@ namespace gl { void initModuleGl(); int getSwapInterval(); void setSwapInterval(int swapInterval); + bool queryCurrentRendererIntegerMESA(int attr, unsigned int *value); } #endif // hifi_gpu_GPUConfig_h diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 3e5043003b..2d0f31cd93 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -10,11 +10,13 @@ // #include "GLBackend.h" + #include #include #include #include #include +#include "gl/Config.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -105,13 +107,27 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = }; #define GL_GET_INTEGER(NAME) glGetIntegerv(GL_##NAME, &const_cast(NAME)); - + +#define BYTES_PER_KIB 1024L +#define BYTES_PER_MIB (1024L * BYTES_PER_KIB) + GLint GLBackend::MAX_TEXTURE_IMAGE_UNITS{ 0 }; GLint GLBackend::MAX_UNIFORM_BUFFER_BINDINGS{ 0 }; GLint GLBackend::MAX_COMBINED_UNIFORM_BLOCKS{ 0 }; GLint GLBackend::MAX_COMBINED_TEXTURE_IMAGE_UNITS{ 0 }; GLint GLBackend::MAX_UNIFORM_BLOCK_SIZE{ 0 }; GLint GLBackend::UNIFORM_BUFFER_OFFSET_ALIGNMENT{ 1 }; +GLint GLBackend::GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX{ 0 }; +GLint GLBackend::GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX{ 0 }; +GLint GLBackend::GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX{ 0 }; +GLint GLBackend::TEXTURE_FREE_MEMORY_ATI{ 0 }; + +size_t GLBackend::_total_memory{ 0 }; +size_t GLBackend::_dedicated_memory{ 0 }; +GLBackend::VideoCardType GLBackend::_video_card{ GLBackend::Unknown }; + + +#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 void GLBackend::init() { static std::once_flag once; @@ -132,13 +148,54 @@ void GLBackend::init() { GL_GET_INTEGER(MAX_UNIFORM_BLOCK_SIZE); GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT); + if ( vendor.contains("NVIDIA") ) { + qCDebug(gpugllogging) << "NVIDIA card detected"; + GL_GET_INTEGER(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX); + GL_GET_INTEGER(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX); + GL_GET_INTEGER(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX); + + qCDebug(gpugllogging) << "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: " << GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX; + qCDebug(gpugllogging) << "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: " << GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX; + qCDebug(gpugllogging) << "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: " << GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX; + qCDebug(gpugllogging) << "sz: " << sizeof(_total_memory); + + _total_memory = GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX * BYTES_PER_KIB; + _dedicated_memory = GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX * BYTES_PER_KIB; + _video_card = NVIDIA; + + + } else if ( vendor.contains("ATI")) { + qCDebug(gpugllogging) << "ATI card detected"; + GL_GET_INTEGER(TEXTURE_FREE_MEMORY_ATI); + + _total_memory = TEXTURE_FREE_MEMORY_ATI * BYTES_PER_KIB; + _dedicated_memory = _total_memory; + _video_card = ATI; + } else if ( vendor.contains("Intel")) { + unsigned int mem; + + if ( ::gl::queryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &mem) ) { + _total_memory = mem * BYTES_PER_MIB; + _dedicated_memory = _total_memory; + } + } else { + qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor; + _video_card = Unknown; + _dedicated_memory = 0; + _total_memory = 0; + } + + qCDebug(gpugllogging) << "dedicated: " << _dedicated_memory; + qCDebug(gpugllogging) << "total: " << _total_memory; + + LOG_GL_CONTEXT_INFO(gpugllogging, contextInfo); - GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); + // From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers. qCDebug(gpugllogging) << "GPU:"; - qCDebug(gpugllogging) << "\tcard:" << gpu->getName(); - qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver(); - qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB"; + qCDebug(gpugllogging) << "\ttotal memory:" << (_total_memory / BYTES_PER_KIB) << "KB"; + qCDebug(gpugllogging) << "\tdedicated memory:" << (_dedicated_memory / BYTES_PER_KIB) << "KB"; + qCDebug(gpugllogging) << "\tavailable memory:" << (getAvailableMemory() / BYTES_PER_KIB) << "KB"; qCDebug(gpugllogging) << "Limits:"; qCDebug(gpugllogging) << "\tmax textures:" << MAX_TEXTURE_IMAGE_UNITS; qCDebug(gpugllogging) << "\tmax texture binding:" << MAX_COMBINED_TEXTURE_IMAGE_UNITS; @@ -152,6 +209,24 @@ void GLBackend::init() { }); } +size_t GLBackend::getAvailableMemory() { + GLint mem; + + switch( _video_card ) { + case NVIDIA: + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &mem); + return mem * BYTES_PER_KIB; + case ATI: + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &mem); + return mem * BYTES_PER_KIB; + case Unknown: + break; + } + + return 0; + +} + GLBackend::GLBackend(bool syncCache) { _pipeline._cameraCorrectionBuffer._buffer->flush(); initShaderBinaryCache(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index a13718f5a2..1c8230c972 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -67,6 +67,12 @@ protected: GLBackend(); public: + enum VideoCardType { + ATI, + NVIDIA, + Unknown + }; + #if defined(USE_GLES) // https://www.khronos.org/registry/OpenGL-Refpages/es3/html/glGet.xhtml static const GLint MIN_REQUIRED_TEXTURE_IMAGE_UNITS = 16; @@ -89,6 +95,24 @@ public: static GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS; static GLint MAX_UNIFORM_BLOCK_SIZE; static GLint UNIFORM_BUFFER_OFFSET_ALIGNMENT; + static GLint GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX; + static GLint GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX; + static GLint GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX; + static GLint TEXTURE_FREE_MEMORY_ATI; + + + static size_t _total_memory; + static size_t _dedicated_memory; + static VideoCardType _video_card; + + + static size_t getTotalMemory() { return _total_memory; } + static size_t getDedicatedMemory() { return _dedicated_memory; } + + static size_t getAvailableMemory(); + + + virtual ~GLBackend(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index c9a5856a8d..98c8244c91 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -185,7 +185,11 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { size_t allowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage(); if (0 == allowedMemoryAllocation) { - allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY; + allowedMemoryAllocation = GLBackend::getTotalMemory(); + if ( 0 == allowedMemoryAllocation ) { + // Last resort, if we failed to detect + allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY; + } } // Clear any defunct textures (weak pointers that no longer have a valid texture) From 349ba16a3c251e8d6df4884fb6e15de78a3b067f Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Fri, 7 Aug 2020 22:45:27 +0200 Subject: [PATCH 2/7] Review fixes --- libraries/gl/src/gl/Config.cpp | 2 +- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 52 +++++++++++-------- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 11 ++-- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/libraries/gl/src/gl/Config.cpp b/libraries/gl/src/gl/Config.cpp index 759cbb98a8..ab1dfac97c 100644 --- a/libraries/gl/src/gl/Config.cpp +++ b/libraries/gl/src/gl/Config.cpp @@ -75,7 +75,7 @@ static void* getGlProcessAddress(const char *namez) { #else -typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); +typedef Bool (*PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC QueryCurrentRendererIntegerMESA; static void* getGlProcessAddress(const char *namez) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 2d0f31cd93..44f2722ac8 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -122,9 +122,9 @@ GLint GLBackend::GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX{ 0 }; GLint GLBackend::GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX{ 0 }; GLint GLBackend::TEXTURE_FREE_MEMORY_ATI{ 0 }; -size_t GLBackend::_total_memory{ 0 }; -size_t GLBackend::_dedicated_memory{ 0 }; -GLBackend::VideoCardType GLBackend::_video_card{ GLBackend::Unknown }; +size_t GLBackend::_totalMemory{ 0 }; +size_t GLBackend::_dedicatedMemory{ 0 }; +GLBackend::VideoCardType GLBackend::_videoCard{ GLBackend::Unknown }; #define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 @@ -148,7 +148,7 @@ void GLBackend::init() { GL_GET_INTEGER(MAX_UNIFORM_BLOCK_SIZE); GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT); - if ( vendor.contains("NVIDIA") ) { + if (vendor.contains("NVIDIA") ) { qCDebug(gpugllogging) << "NVIDIA card detected"; GL_GET_INTEGER(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX); GL_GET_INTEGER(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX); @@ -157,44 +157,48 @@ void GLBackend::init() { qCDebug(gpugllogging) << "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: " << GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX; qCDebug(gpugllogging) << "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: " << GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX; qCDebug(gpugllogging) << "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: " << GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX; - qCDebug(gpugllogging) << "sz: " << sizeof(_total_memory); + qCDebug(gpugllogging) << "sz: " << sizeof(_totalMemory); - _total_memory = GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX * BYTES_PER_KIB; - _dedicated_memory = GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX * BYTES_PER_KIB; - _video_card = NVIDIA; + _totalMemory = GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX * BYTES_PER_KIB; + _dedicatedMemory = GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX * BYTES_PER_KIB; + _videoCard = NVIDIA; - } else if ( vendor.contains("ATI")) { + } else if (vendor.contains("ATI")) { qCDebug(gpugllogging) << "ATI card detected"; GL_GET_INTEGER(TEXTURE_FREE_MEMORY_ATI); - _total_memory = TEXTURE_FREE_MEMORY_ATI * BYTES_PER_KIB; - _dedicated_memory = _total_memory; - _video_card = ATI; - } else if ( vendor.contains("Intel")) { + _totalMemory = TEXTURE_FREE_MEMORY_ATI * BYTES_PER_KIB; + _dedicatedMemory = _totalMemory; + _videoCard = ATI; + } else if (vendor.contains("Intel")) { unsigned int mem; if ( ::gl::queryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &mem) ) { - _total_memory = mem * BYTES_PER_MIB; - _dedicated_memory = _total_memory; + _totalMemory = mem * BYTES_PER_MIB; + _dedicatedMemory = _totalMemory; + _videoCard = Intel; } } else { qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor; - _video_card = Unknown; - _dedicated_memory = 0; - _total_memory = 0; + _videoCard = Unknown; + _dedicatedMemory = 0; + _totalMemory = 0; } - qCDebug(gpugllogging) << "dedicated: " << _dedicated_memory; - qCDebug(gpugllogging) << "total: " << _total_memory; + qCDebug(gpugllogging) << "dedicated: " << _dedicatedMemory; + qCDebug(gpugllogging) << "total: " << _totalMemory; LOG_GL_CONTEXT_INFO(gpugllogging, contextInfo); + GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); // From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers. qCDebug(gpugllogging) << "GPU:"; - qCDebug(gpugllogging) << "\ttotal memory:" << (_total_memory / BYTES_PER_KIB) << "KB"; - qCDebug(gpugllogging) << "\tdedicated memory:" << (_dedicated_memory / BYTES_PER_KIB) << "KB"; + qCDebug(gpugllogging) << "\tcard:" << gpu->getName(); + qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver(); + qCDebug(gpugllogging) << "\ttotal memory:" << (_totalMemory / BYTES_PER_KIB) << "KB"; + qCDebug(gpugllogging) << "\tdedicated memory:" << (_dedicatedMemory / BYTES_PER_KIB) << "KB"; qCDebug(gpugllogging) << "\tavailable memory:" << (getAvailableMemory() / BYTES_PER_KIB) << "KB"; qCDebug(gpugllogging) << "Limits:"; qCDebug(gpugllogging) << "\tmax textures:" << MAX_TEXTURE_IMAGE_UNITS; @@ -212,13 +216,15 @@ void GLBackend::init() { size_t GLBackend::getAvailableMemory() { GLint mem; - switch( _video_card ) { + switch( _videoCard ) { case NVIDIA: glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &mem); return mem * BYTES_PER_KIB; case ATI: glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &mem); return mem * BYTES_PER_KIB; + case Intel: + return 0; // Don't know the current value case Unknown: break; } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 1c8230c972..ca44b897d9 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -70,6 +70,7 @@ public: enum VideoCardType { ATI, NVIDIA, + Intel, Unknown }; @@ -101,13 +102,13 @@ public: static GLint TEXTURE_FREE_MEMORY_ATI; - static size_t _total_memory; - static size_t _dedicated_memory; - static VideoCardType _video_card; + static size_t _totalMemory; + static size_t _dedicatedMemory; + static VideoCardType _videoCard; - static size_t getTotalMemory() { return _total_memory; } - static size_t getDedicatedMemory() { return _dedicated_memory; } + static size_t getTotalMemory() { return _totalMemory; } + static size_t getDedicatedMemory() { return _dedicatedMemory; } static size_t getAvailableMemory(); From 991cfdae699d5d971b536bcb7b3e839c5c853455 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Sat, 8 Aug 2020 01:31:49 +0200 Subject: [PATCH 3/7] Automatic texture memory based on free memory --- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 24 +++++++++++-- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 1 + .../src/gpu/gl/GLTextureTransfer.cpp | 36 ++++++++++++++++--- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 44f2722ac8..1dd58904e8 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -148,6 +148,8 @@ void GLBackend::init() { GL_GET_INTEGER(MAX_UNIFORM_BLOCK_SIZE); GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT); + GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); + if (vendor.contains("NVIDIA") ) { qCDebug(gpugllogging) << "NVIDIA card detected"; GL_GET_INTEGER(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX); @@ -178,12 +180,17 @@ void GLBackend::init() { _totalMemory = mem * BYTES_PER_MIB; _dedicatedMemory = _totalMemory; _videoCard = Intel; + } else { + qCWarning(gpugllogging) << "Intel card on non-Linux system, trying GPUIdent fallback"; + _videoCard = Unknown; + _dedicatedMemory = gpu->getMemory(); + _totalMemory = _dedicatedMemory; } } else { qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor; _videoCard = Unknown; - _dedicatedMemory = 0; - _totalMemory = 0; + _dedicatedMemory = gpu->getMemory(); + _totalMemory = _dedicatedMemory; } qCDebug(gpugllogging) << "dedicated: " << _dedicatedMemory; @@ -191,7 +198,7 @@ void GLBackend::init() { LOG_GL_CONTEXT_INFO(gpugllogging, contextInfo); - GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); + // From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers. qCDebug(gpugllogging) << "GPU:"; @@ -233,6 +240,17 @@ size_t GLBackend::getAvailableMemory() { } +bool GLBackend::availableMemoryKnown() { + switch( _videoCard ) { + case NVIDIA: return true; + case ATI: return true; + case Intel: return false; + case Unknown: return false; + } + + return false; +} + GLBackend::GLBackend(bool syncCache) { _pipeline._cameraCorrectionBuffer._buffer->flush(); initShaderBinaryCache(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index ca44b897d9..3be1dfad55 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -111,6 +111,7 @@ public: static size_t getDedicatedMemory() { return _dedicatedMemory; } static size_t getAvailableMemory(); + static bool availableMemoryKnown(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index 98c8244c91..c39dc2917d 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -19,6 +19,8 @@ #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 #define NO_BUFFER_WORK_SLEEP_TIME_MS 2 #define THREADED_TEXTURE_BUFFERING 1 +#define MAX_AUTO_FRACTION_OF_TOTAL_MEMORY 0.8f +#define AUTO_RESERVE_TEXTURE_MEMORY MB_TO_BYTES(64) static const size_t DEFAULT_ALLOWED_TEXTURE_MEMORY = MB_TO_BYTES(DEFAULT_ALLOWED_TEXTURE_MEMORY_MB); @@ -183,12 +185,24 @@ void GLTextureTransferEngineDefault::manageMemory() { void GLTextureTransferEngineDefault::updateMemoryPressure() { PROFILE_RANGE(render_gpu_gl, __FUNCTION__); + bool useAvailableGlMemory = false; size_t allowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage(); + if (0 == allowedMemoryAllocation) { - allowedMemoryAllocation = GLBackend::getTotalMemory(); - if ( 0 == allowedMemoryAllocation ) { - // Last resort, if we failed to detect - allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY; + // Automatic allocation + + if ( GLBackend::availableMemoryKnown() ) { + // If we know how much is free, then we use that + useAvailableGlMemory = true; + } else { + // We don't know how much is free, so leave some reasonable spare room + // and hope it works. + allowedMemoryAllocation = GLBackend::getTotalMemory() * MAX_AUTO_FRACTION_OF_TOTAL_MEMORY; + + if ( 0 == allowedMemoryAllocation ) { + // Last resort, if we failed to detect + allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY; + } } } @@ -222,7 +236,19 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { Backend::textureResourceIdealGPUMemSize.set(idealMemoryAllocation); size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation; - float pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation; + float pressure = 0; + + if ( useAvailableGlMemory ) { + float total_mem = GLBackend::getTotalMemory(); + float avail_mem = GLBackend::getAvailableMemory() - AUTO_RESERVE_TEXTURE_MEMORY; + if ( avail_mem < 0 ) { + avail_mem = 0; + } + + pressure = (total_mem - avail_mem) / total_mem; + } else { + pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation; + } // If we're oversubscribed we need to demote textures IMMEDIATELY if (pressure > OVERSUBSCRIBED_PRESSURE_VALUE && canDemote) { From 482211d6eb6fd7e257009391614666d8c6126494 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Sun, 9 Aug 2020 01:25:39 +0200 Subject: [PATCH 4/7] Try the MESA pathway always if not ATI or NVIDIA This will work fine on non-Linux systems, because the query should simply fail on systems that don't support it. This should improve functionality on nouveau --- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 23 ++++++++----------- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 1dd58904e8..63cbf804d1 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -149,6 +149,7 @@ void GLBackend::init() { GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT); GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); + unsigned int mem; if (vendor.contains("NVIDIA") ) { qCDebug(gpugllogging) << "NVIDIA card detected"; @@ -173,21 +174,15 @@ void GLBackend::init() { _totalMemory = TEXTURE_FREE_MEMORY_ATI * BYTES_PER_KIB; _dedicatedMemory = _totalMemory; _videoCard = ATI; - } else if (vendor.contains("Intel")) { - unsigned int mem; - - if ( ::gl::queryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &mem) ) { + } else if ( ::gl::queryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &mem) ) { + // This works only on Linux. queryCurrentRendererIntegerMESA will return false if the + // function is not supported because we're not on Linux, or for any other reason. + qCDebug(gpugllogging) << "MESA card detected"; _totalMemory = mem * BYTES_PER_MIB; _dedicatedMemory = _totalMemory; - _videoCard = Intel; - } else { - qCWarning(gpugllogging) << "Intel card on non-Linux system, trying GPUIdent fallback"; - _videoCard = Unknown; - _dedicatedMemory = gpu->getMemory(); - _totalMemory = _dedicatedMemory; - } + _videoCard = MESA; } else { - qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor; + qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor << "; renderer " << renderer << ", trying fallback"; _videoCard = Unknown; _dedicatedMemory = gpu->getMemory(); _totalMemory = _dedicatedMemory; @@ -230,7 +225,7 @@ size_t GLBackend::getAvailableMemory() { case ATI: glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &mem); return mem * BYTES_PER_KIB; - case Intel: + case MESA: return 0; // Don't know the current value case Unknown: break; @@ -244,7 +239,7 @@ bool GLBackend::availableMemoryKnown() { switch( _videoCard ) { case NVIDIA: return true; case ATI: return true; - case Intel: return false; + case MESA: return false; case Unknown: return false; } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 3be1dfad55..0c8676493b 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -70,7 +70,7 @@ public: enum VideoCardType { ATI, NVIDIA, - Intel, + MESA, Unknown }; From 0d4987878eac7b0e245fa5be2eb97964dd136179 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Thu, 13 Aug 2020 01:48:41 +0200 Subject: [PATCH 5/7] Review fixes --- libraries/gl/src/gl/Config.h | 2 +- libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp | 13 ++++++++----- .../src/gpu/gl/GLTextureTransfer.cpp | 16 ++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/libraries/gl/src/gl/Config.h b/libraries/gl/src/gl/Config.h index 8defbc5bca..1c80cf4a10 100644 --- a/libraries/gl/src/gl/Config.h +++ b/libraries/gl/src/gl/Config.h @@ -52,7 +52,7 @@ namespace gl { void initModuleGl(); int getSwapInterval(); void setSwapInterval(int swapInterval); - bool queryCurrentRendererIntegerMESA(int attr, unsigned int *value); + bool queryCurrentRendererIntegerMESA(int attr, unsigned int *value); } #endif // hifi_gpu_GPUConfig_h diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 63cbf804d1..602ab1c320 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -160,7 +160,6 @@ void GLBackend::init() { qCDebug(gpugllogging) << "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: " << GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX; qCDebug(gpugllogging) << "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: " << GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX; qCDebug(gpugllogging) << "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: " << GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX; - qCDebug(gpugllogging) << "sz: " << sizeof(_totalMemory); _totalMemory = GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX * BYTES_PER_KIB; _dedicatedMemory = GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX * BYTES_PER_KIB; @@ -237,10 +236,14 @@ size_t GLBackend::getAvailableMemory() { bool GLBackend::availableMemoryKnown() { switch( _videoCard ) { - case NVIDIA: return true; - case ATI: return true; - case MESA: return false; - case Unknown: return false; + case NVIDIA: + return true; + case ATI: + return true; + case MESA: + return false; + case Unknown: + return false; } return false; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index c39dc2917d..6a88fd2c50 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -191,7 +191,7 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { if (0 == allowedMemoryAllocation) { // Automatic allocation - if ( GLBackend::availableMemoryKnown() ) { + if (GLBackend::availableMemoryKnown()) { // If we know how much is free, then we use that useAvailableGlMemory = true; } else { @@ -199,7 +199,7 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { // and hope it works. allowedMemoryAllocation = GLBackend::getTotalMemory() * MAX_AUTO_FRACTION_OF_TOTAL_MEMORY; - if ( 0 == allowedMemoryAllocation ) { + if (0 == allowedMemoryAllocation) { // Last resort, if we failed to detect allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY; } @@ -238,14 +238,14 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation; float pressure = 0; - if ( useAvailableGlMemory ) { - float total_mem = GLBackend::getTotalMemory(); - float avail_mem = GLBackend::getAvailableMemory() - AUTO_RESERVE_TEXTURE_MEMORY; - if ( avail_mem < 0 ) { - avail_mem = 0; + if (useAvailableGlMemory) { + float totalMem = GLBackend::getTotalMemory(); + float availMem = GLBackend::getAvailableMemory() - AUTO_RESERVE_TEXTURE_MEMORY; + if (availMem < 0) { + availMem = 0; } - pressure = (total_mem - avail_mem) / total_mem; + pressure = (totalMem - availMem) / totalMem; } else { pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation; } From 7a186bba34df9b89ced27eae33d739ebc80b60f4 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Sun, 18 Oct 2020 22:13:28 +0200 Subject: [PATCH 6/7] Fix issues with integer overflow in memory pressure calculations --- .../gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index 6a88fd2c50..2b9b209c67 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -239,13 +239,16 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { float pressure = 0; if (useAvailableGlMemory) { - float totalMem = GLBackend::getTotalMemory(); - float availMem = GLBackend::getAvailableMemory() - AUTO_RESERVE_TEXTURE_MEMORY; - if (availMem < 0) { + size_t totalMem = GLBackend::getTotalMemory(); + size_t availMem = GLBackend::getAvailableMemory(); + + if (availMem >= AUTO_RESERVE_TEXTURE_MEMORY) { + availMem -= AUTO_RESERVE_TEXTURE_MEMORY; + } else { availMem = 0; } - pressure = (totalMem - availMem) / totalMem; + pressure = ((float)totalMem - (float)availMem) / (float)totalMem; } else { pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation; } From 32843133993c7350d4108a8c39f5b3072bb20c6d Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Tue, 27 Oct 2020 01:19:22 +0100 Subject: [PATCH 7/7] Mark font textures as something that shouldn't be downscaled --- libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp | 4 ++-- libraries/gpu/src/gpu/Texture.h | 4 ++++ libraries/render-utils/src/text/Font.cpp | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index 2b9b209c67..af865b3ad7 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -223,7 +223,7 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() { idealMemoryAllocation += texture->evalTotalSize(); // Track how much we're actually using totalVariableMemoryAllocation += gltexture->size(); - if (vartexture->canDemote()) { + if (!gltexture->_gpuObject.getImportant() && vartexture->canDemote()) { canDemote |= true; } if (vartexture->canPromote()) { @@ -503,7 +503,7 @@ void GLTextureTransferEngineDefault::processDemotes(size_t reliefRequired, const for (const auto& texture : strongTextures) { GLTexture* gltexture = Backend::getGPUObject(*texture); GLVariableAllocationSupport* vargltexture = dynamic_cast(gltexture); - if (vargltexture->canDemote()) { + if (!gltexture->_gpuObject.getImportant() && vargltexture->canDemote()) { demoteQueue.push({ texture, (float)gltexture->size() }); } } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index debedf02a5..54c7d49421 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -571,6 +571,9 @@ public: void setExternalRecycler(const ExternalRecycler& recycler); ExternalRecycler getExternalRecycler() const; + bool getImportant() const { return _important; } + void setImportant(bool important) { _important = important; } + const GPUObjectPointer gpuObject {}; ExternalUpdates getUpdates() const; @@ -632,6 +635,7 @@ protected: bool _autoGenerateMips = false; bool _isIrradianceValid = false; bool _defined = false; + bool _important = false; static TexturePointer create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 024be6598d..a30bbad0e5 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -260,6 +260,7 @@ void Font::read(QIODevice& in) { gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR)); _texture->setStoredMipFormat(formatMip); _texture->assignStoredMip(0, image.sizeInBytes(), image.constBits()); + _texture->setImportant(true); } void Font::setupGPU() {