2018-10-04 06:52:51 +08:00
/*
2024-05-22 22:12:59 +08:00
* Copyright ( C ) 2018 - 2024 Intel Corporation
2018-10-04 06:52:51 +08:00
*
* SPDX - License - Identifier : MIT
*
*/
2020-02-24 05:44:01 +08:00
# include "shared/source/os_interface/windows/wddm_residency_controller.h"
2019-02-27 18:39:32 +08:00
2024-08-29 18:13:00 +08:00
# include "shared/source/command_stream/command_stream_receiver.h"
2020-02-24 05:44:01 +08:00
# include "shared/source/debug_settings/debug_settings_manager.h"
# include "shared/source/os_interface/windows/wddm/wddm.h"
# include "shared/source/os_interface/windows/wddm_allocation.h"
# include "shared/source/os_interface/windows/wddm_residency_allocations_container.h"
# include "shared/source/utilities/spinlock.h"
2018-10-04 06:52:51 +08:00
2019-03-26 18:59:46 +08:00
namespace NEO {
2018-10-04 06:52:51 +08:00
2018-10-30 21:40:02 +08:00
WddmResidencyController : : WddmResidencyController ( Wddm & wddm , uint32_t osContextId ) : wddm ( wddm ) , osContextId ( osContextId ) {
2018-11-14 21:35:45 +08:00
}
void WddmResidencyController : : registerCallback ( ) {
2018-11-15 18:44:37 +08:00
this - > trimCallbackHandle = wddm . registerTrimCallback ( WddmResidencyController : : trimCallback , * this ) ;
2018-10-30 21:40:02 +08:00
}
WddmResidencyController : : ~ WddmResidencyController ( ) {
auto lock = this - > acquireTrimCallbackLock ( ) ;
2018-11-15 18:44:37 +08:00
wddm . unregisterTrimCallback ( WddmResidencyController : : trimCallback , this - > trimCallbackHandle ) ;
2018-10-30 21:40:02 +08:00
lock . unlock ( ) ;
// Wait for lock to ensure trimCallback ended
lock . lock ( ) ;
}
2018-10-04 06:52:51 +08:00
2018-10-16 21:53:39 +08:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireLock ( ) {
return std : : unique_lock < SpinLock > { this - > lock } ;
2018-10-04 06:52:51 +08:00
}
2018-10-16 21:53:39 +08:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireTrimCallbackLock ( ) {
return std : : unique_lock < SpinLock > { this - > trimCallbackLock } ;
2018-10-15 23:12:55 +08:00
}
2018-10-22 21:59:26 +08:00
void WddmResidencyController : : resetMonitoredFenceParams ( D3DKMT_HANDLE & handle , uint64_t * cpuAddress , D3DGPU_VIRTUAL_ADDRESS & gpuAddress ) {
monitoredFence . lastSubmittedFence = 0 ;
monitoredFence . currentFenceValue = 1 ;
monitoredFence . fenceHandle = handle ;
monitoredFence . cpuAddress = cpuAddress ;
monitoredFence . gpuAddress = gpuAddress ;
}
2024-08-07 00:13:06 +08:00
/**
* @ brief Makes resident passed allocations on a device
*
* @ param [ in ] allocationsForResidency container of allocations which need to be resident .
* @ param [ out ] requiresBlockingResidencyHandling flag indicating whether wait for paging fence must be handled in user thread .
* Setting to false means that it can be handled in background thread , which will signal semaphore after paging fence reaches required value .
*
2024-08-22 18:25:49 +08:00
* @ note This method filters allocations which are already resident . After calling this method , passed allocationsForResidency will contain
* only allocations which were not resident before .
2024-08-07 00:13:06 +08:00
*
* @ return returns true if all allocations either succeeded or are pending to be resident
*/
2024-08-22 18:25:49 +08:00
bool WddmResidencyController : : makeResidentResidencyAllocations ( ResidencyContainer & allocationsForResidency , bool & requiresBlockingResidencyHandling ) {
2024-09-05 20:38:10 +08:00
const size_t residencyCount = allocationsForResidency . size ( ) ;
2024-08-07 17:31:59 +08:00
requiresBlockingResidencyHandling = false ;
2024-08-07 00:13:06 +08:00
if ( debugManager . flags . WaitForPagingFenceInController . get ( ) ! = - 1 ) {
requiresBlockingResidencyHandling = ! debugManager . flags . WaitForPagingFenceInController . get ( ) ;
}
2018-11-05 22:47:32 +08:00
auto lock = this - > acquireLock ( ) ;
2024-10-07 21:43:59 +08:00
backupResidencyContainer = allocationsForResidency ;
2024-09-05 20:38:10 +08:00
auto totalSize = fillHandlesContainer ( allocationsForResidency , requiresBlockingResidencyHandling ) ;
2018-11-05 22:47:32 +08:00
bool result = true ;
2024-09-05 20:38:10 +08:00
if ( ! handlesForResidency . empty ( ) ) {
2018-11-05 22:47:32 +08:00
uint64_t bytesToTrim = 0 ;
2024-09-05 20:38:10 +08:00
while ( ( result = wddm . makeResident ( handlesForResidency . data ( ) , static_cast < uint32_t > ( handlesForResidency . size ( ) ) , false , & bytesToTrim , totalSize ) ) = = false ) {
2018-11-05 22:47:32 +08:00
this - > setMemoryBudgetExhausted ( ) ;
2024-09-24 18:58:26 +08:00
const bool trimmingDone = this - > trimResidencyToBudget ( bytesToTrim ) ;
2024-10-07 21:43:59 +08:00
allocationsForResidency = backupResidencyContainer ;
2018-11-15 21:45:35 +08:00
if ( ! trimmingDone ) {
2019-07-12 22:50:14 +08:00
auto evictionStatus = wddm . getTemporaryResourcesContainer ( ) - > evictAllResources ( ) ;
2024-09-05 20:38:10 +08:00
totalSize = fillHandlesContainer ( allocationsForResidency , requiresBlockingResidencyHandling ) ;
2023-12-13 17:17:24 +08:00
if ( evictionStatus = = MemoryOperationsStatus : : success ) {
2019-01-16 22:09:33 +08:00
continue ;
}
2023-12-13 17:17:24 +08:00
DEBUG_BREAK_IF ( evictionStatus ! = MemoryOperationsStatus : : memoryNotFound ) ;
2023-05-31 21:55:08 +08:00
do {
2024-09-05 20:38:10 +08:00
result = wddm . makeResident ( handlesForResidency . data ( ) , static_cast < uint32_t > ( handlesForResidency . size ( ) ) , true , & bytesToTrim , totalSize ) ;
2023-11-30 16:32:25 +08:00
} while ( debugManager . flags . WaitForMemoryRelease . get ( ) & & result = = false ) ;
2018-11-05 22:47:32 +08:00
break ;
}
2024-09-05 20:38:10 +08:00
totalSize = fillHandlesContainer ( allocationsForResidency , requiresBlockingResidencyHandling ) ;
2018-11-05 22:47:32 +08:00
}
}
2024-09-05 20:38:10 +08:00
const auto currentFence = this - > getMonitoredFence ( ) . currentFenceValue ;
2018-11-05 22:47:32 +08:00
if ( result = = true ) {
2024-09-05 20:38:10 +08:00
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2024-10-07 21:43:59 +08:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( backupResidencyContainer [ i ] ) ;
2018-11-28 18:01:41 +08:00
allocation - > getResidencyData ( ) . resident [ osContextId ] = true ;
2024-09-05 20:38:10 +08:00
allocation - > getResidencyData ( ) . updateCompletionData ( currentFence , this - > osContextId ) ;
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , " fence value to reach for eviction = " , currentFence ) ;
2018-11-05 22:47:32 +08:00
for ( uint32_t allocationId = 0 ; allocationId < allocation - > fragmentsStorage . fragmentCount ; allocationId + + ) {
auto residencyData = allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . residency ;
2018-11-28 18:01:41 +08:00
residencyData - > resident [ osContextId ] = true ;
2024-09-05 20:38:10 +08:00
residencyData - > updateCompletionData ( currentFence , this - > osContextId ) ;
2018-11-05 22:47:32 +08:00
}
}
}
return result ;
}
2024-09-05 20:38:10 +08:00
/**
* @ brief Fills containers related to residency handling based on passed allocations . For each allocation ,
* if it ' s not yet resident , this allocation and it ' s handle are added to associated containers .
*
* @ return returns total size in bytes of allocations which are not yet resident .
*/
2024-10-07 21:43:59 +08:00
size_t WddmResidencyController : : fillHandlesContainer ( ResidencyContainer & allocationsForResidency , bool & requiresBlockingResidencyHandling ) {
2024-09-05 20:38:10 +08:00
size_t totalSize = 0 ;
const size_t residencyCount = allocationsForResidency . size ( ) ;
handlesForResidency . clear ( ) ;
handlesForResidency . reserve ( residencyCount ) ;
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " currentFenceValue = " , this - > getMonitoredFence ( ) . currentFenceValue ) ;
2024-10-07 21:43:59 +08:00
auto checkIfAlreadyResident = [ & ] ( GraphicsAllocation * alloc ) {
WddmAllocation * allocation = static_cast < WddmAllocation * > ( alloc ) ;
2024-09-05 20:38:10 +08:00
ResidencyData & residencyData = allocation - > getResidencyData ( ) ;
static constexpr int maxFragments = 3 ;
const auto fragmentCount = allocation - > fragmentsStorage . fragmentCount ;
UNRECOVERABLE_IF ( fragmentCount > maxFragments ) ;
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , residencyData . resident [ osContextId ] ? " resident " : " not resident " ) ;
bool isAlreadyResident = true ;
if ( fragmentCount > 0 ) {
for ( uint32_t allocationId = 0 ; allocationId < fragmentCount ; allocationId + + ) {
2024-10-07 21:43:59 +08:00
handlesForResidency . push_back ( static_cast < OsHandleWin * > ( allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . osHandleStorage ) - > handle ) ;
requiresBlockingResidencyHandling | = ( allocation - > getAllocationType ( ) ! = AllocationType : : buffer & & allocation - > getAllocationType ( ) ! = AllocationType : : bufferHostMemory ) ;
isAlreadyResident = false ;
2024-09-05 20:38:10 +08:00
}
} else if ( ! residencyData . resident [ osContextId ] ) {
for ( uint32_t gmmId = 0 ; gmmId < allocation - > getNumGmms ( ) ; + + gmmId ) {
handlesForResidency . push_back ( allocation - > getHandle ( gmmId ) ) ;
requiresBlockingResidencyHandling | = ( allocation - > getAllocationType ( ) ! = AllocationType : : buffer & & allocation - > getAllocationType ( ) ! = AllocationType : : bufferHostMemory ) ;
isAlreadyResident = false ;
}
}
if ( ! isAlreadyResident ) {
totalSize + = allocation - > getAlignedSize ( ) ;
}
2024-10-07 21:43:59 +08:00
return isAlreadyResident ;
} ;
allocationsForResidency . erase ( std : : remove_if ( allocationsForResidency . begin ( ) , allocationsForResidency . end ( ) , checkIfAlreadyResident ) , allocationsForResidency . end ( ) ) ;
2024-09-05 20:38:10 +08:00
return totalSize ;
}
2019-12-19 21:02:05 +08:00
bool WddmResidencyController : : isInitialized ( ) const {
2021-05-21 07:17:57 +08:00
bool requiresTrimCallbacks = OSInterface : : requiresSupportForWddmTrimNotification ;
2023-11-30 16:32:25 +08:00
requiresTrimCallbacks = requiresTrimCallbacks & & ( false = = debugManager . flags . DoNotRegisterTrimCallback . get ( ) ) ;
2021-05-21 07:17:57 +08:00
if ( requiresTrimCallbacks ) {
2019-12-19 21:02:05 +08:00
return trimCallbackHandle ! = nullptr ;
}
return true ;
}
2024-08-22 18:25:49 +08:00
void WddmResidencyController : : setCommandStreamReceiver ( CommandStreamReceiver * csr ) {
this - > csr = csr ;
}
2024-08-29 18:13:00 +08:00
void WddmResidencyController : : removeAllocation ( ResidencyContainer & container , GraphicsAllocation * gfxAllocation ) {
std : : unique_lock < std : : mutex > lock1 ( this - > lock , std : : defer_lock ) ;
std : : unique_lock < std : : mutex > lock2 ( this - > trimCallbackLock , std : : defer_lock ) ;
std : : lock ( lock1 , lock2 ) ;
auto iter = std : : find ( container . begin ( ) , container . end ( ) , gfxAllocation ) ;
if ( iter ! = container . end ( ) ) {
container . erase ( iter ) ;
}
}
2019-03-26 18:59:46 +08:00
} // namespace NEO