From a911b6324734858dd448e289f458e8d8e31162af Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 15 Mar 2018 18:46:56 -0400 Subject: [PATCH] Fix memory issues. Wrap each queue submission in a dedicated @autoreleasepool. Fix memory leak during creation of global format mappings. --- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 8 ++++++-- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 9 +++++---- MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 9 +++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index c1b4f5f6..a4fe5300 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -53,10 +53,14 @@ MVKQueueFamily::~MVKQueueFamily() { #pragma mark Queue submissions -/** Submits the specified submission object to the execution queue. */ +/** + * Submits the specified submission object to the execution queue, wrapping each submission + * in a dedicated autorelease pool. Relying on the dispatch queue to find time to drain the + * autorelease pool can result in significant memory creep under heavy workloads. + */ void MVKQueue::submit(MVKQueueSubmission* qSubmit) { if ( !qSubmit ) { return; } // Ignore nils - dispatch_async( _execQueue, ^{ qSubmit->execute(); } ); + dispatch_async( _execQueue, ^{ @autoreleasepool { qSubmit->execute(); } } ); } VkResult MVKQueue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index ef309f35..b3a5b5c3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -161,10 +161,11 @@ void MVKSwapchain::markFrameInterval() { if (perfLogCntLimit > 0) { _currentPerfLogFrameCount++; if (_currentPerfLogFrameCount >= perfLogCntLimit) { - MVKLogInfo("Frame interval: %.2f ms. Avg frame interval: %.2f ms. FPS: %.2f.", + MVKLogInfo("Frame interval: %.2f ms. Avg frame interval: %.2f ms. FPS: %.2f. Elapsed time: %.3f seconds.", _performanceStatistics.lastFrameInterval, _performanceStatistics.averageFrameInterval, - _performanceStatistics.averageFramesPerSecond); + _performanceStatistics.averageFramesPerSecond, + mvkGetElapsedMilliseconds() / 1000.0); _currentPerfLogFrameCount = 0; } } @@ -257,8 +258,8 @@ void MVKSwapchain::initFrameIntervalTracking() { _lastFrameTime = mvkGetTimestamp(); // Establish the alpha parameter of a low-pass filter for averaging frame intervals. - double RC_over_dt = 10; - _averageFrameIntervalFilterAlpha = 1.0 / (1 + RC_over_dt); + double RC_over_dt = 10.0; + _averageFrameIntervalFilterAlpha = 1.0 / (1.0 + RC_over_dt); } MVKSwapchain::~MVKSwapchain() { diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 0801e0ec..48b52623 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -427,8 +427,9 @@ typedef unordered_map MVKFormatIndexByVkFormatMap; // Vulkan core formats have small values and are mapped by simple lookup array. // Vulkan extension formats have larger values and are mapped by a map. +// MVKFormatIndexByVkFormatMap held as global pointer to allow it to be populated during global init functions. static uint16_t _fmtDescIndicesByVkFormatsCore[_vkFormatCoreCount]; -static MVKFormatIndexByVkFormatMap _fmtDescIndicesByVkFormatsExt; +static MVKFormatIndexByVkFormatMap* _pFmtDescIndicesByVkFormatsExt; // Metal formats have small values and are mapped by simple lookup array. static uint16_t _fmtDescIndicesByMTLPixelFormats[_mtlFormatCount]; @@ -449,7 +450,7 @@ static void MVKInitFormatMaps() { memset(_fmtDescIndicesByVkFormatsCore, 0, sizeof(_fmtDescIndicesByVkFormatsCore)); memset(_fmtDescIndicesByMTLPixelFormats, 0, sizeof(_fmtDescIndicesByMTLPixelFormats)); - _fmtDescIndicesByVkFormatsExt = MVKFormatIndexByVkFormatMap(); + _pFmtDescIndicesByVkFormatsExt = new MVKFormatIndexByVkFormatMap(); // Iterate through the format descriptions and populate the lookup maps. uint32_t fmtCnt = sizeof(_formatDescriptions) / sizeof(MVKFormatDesc); @@ -465,7 +466,7 @@ static void MVKInitFormatMaps() { if (tfm.vk < _vkFormatCoreCount) { _fmtDescIndicesByVkFormatsCore[tfm.vk] = fmtIdx; } else { - _fmtDescIndicesByVkFormatsExt[tfm.vk] = fmtIdx; + (*_pFmtDescIndicesByVkFormatsExt)[tfm.vk] = fmtIdx; } } @@ -477,7 +478,7 @@ static void MVKInitFormatMaps() { // Return a reference to the format description corresponding to the VkFormat. inline const MVKFormatDesc& formatDescForVkFormat(VkFormat vkFormat) { - uint16_t fmtIdx = (vkFormat < _vkFormatCoreCount) ? _fmtDescIndicesByVkFormatsCore[vkFormat] : _fmtDescIndicesByVkFormatsExt[vkFormat]; + uint16_t fmtIdx = (vkFormat < _vkFormatCoreCount) ? _fmtDescIndicesByVkFormatsCore[vkFormat] : (*_pFmtDescIndicesByVkFormatsExt)[vkFormat]; return _formatDescriptions[fmtIdx]; }