/* * Copyright (c) 2017, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "runtime/helpers/aligned_memory.h" #include "runtime/helpers/ptr_math.h" #include "runtime/gmm_helper/gmm_helper.h" #include "runtime/gmm_helper/resource_info.h" #include "runtime/helpers/surface_formats.h" #include "runtime/memory_manager/deferred_deleter.h" #include "runtime/memory_manager/deferrable_deletion.h" #include "runtime/os_interface/windows/wddm_memory_manager.h" #include "runtime/os_interface/windows/wddm_allocation.h" #include "runtime/os_interface/windows/wddm.h" #include #pragma warning(push) #pragma warning(disable : 4005) #include #pragma warning(pop) #undef max namespace OCLRT { WddmMemoryManager::~WddmMemoryManager() { applyCommonCleanup(); delete this->wddm; } WddmMemoryManager::WddmMemoryManager(bool enable64kbPages, Wddm *wddm) : MemoryManager(enable64kbPages), residencyLock(false) { DEBUG_BREAK_IF(wddm == nullptr); this->wddm = wddm; allocator32Bit = std::unique_ptr(new Allocator32bit(wddm->getHeap32Base(), wddm->getHeap32Size())); wddm->registerTrimCallback(trimCallback, this); asyncDeleterEnabled = DebugManager.flags.EnableDeferredDeleter.get(); if (asyncDeleterEnabled) deferredDeleter = createDeferredDeleter(); } void APIENTRY WddmMemoryManager::trimCallback(_Inout_ D3DKMT_TRIMNOTIFICATION *trimNotification) { WddmMemoryManager *wddmMemMngr = (WddmMemoryManager *)trimNotification->Context; DEBUG_BREAK_IF(wddmMemMngr == nullptr); wddmMemMngr->trimResidency(trimNotification->Flags, trimNotification->NumBytesToTrim); } GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemoryForImage(ImageInfo &imgInfo, Gmm *gmm) { if (!Gmm::allowTiling(*imgInfo.imgDesc)) { delete gmm; return allocateGraphicsMemory(imgInfo.size, MemoryConstants::preferredAlignment); } WddmAllocation allocation(nullptr, imgInfo.size); allocation.gmm = gmm; auto status = wddm->createAllocation(&allocation); if (status == STATUS_GRAPHICS_NO_VIDEO_MEMORY && deferredDeleter) { deferredDeleter->drain(true); status = wddm->createAllocation(&allocation); } allocation.setGpuAddress(allocation.gpuPtr); if (status == STATUS_SUCCESS) { auto *wddmAllocation = new WddmAllocation(allocation); return wddmAllocation; } return nullptr; } GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory64kb(size_t size, size_t alignment, bool forcePin) { size_t sizeAligned = alignUp(size, MemoryConstants::pageSize64k); bool success = true; Gmm *gmm = nullptr; WddmAllocation allocation(nullptr, sizeAligned, nullptr, sizeAligned); gmm = Gmm::create(nullptr, sizeAligned, false); while (success) { allocation.gmm = gmm; success = wddm->createAllocation64k(&allocation); if (!success) break; auto *wddmAllocation = new WddmAllocation(allocation); auto cpuPtr = lockResource(wddmAllocation); wddmAllocation->setLocked(true); wddmAllocation->setAlignedCpuPtr(cpuPtr); // 64kb map is not needed wddm->mapGpuVirtualAddress(wddmAllocation, cpuPtr, sizeAligned, false, false); wddmAllocation->setCpuPtrAndGpuAddress(cpuPtr, (uint64_t)wddmAllocation->gpuPtr); return wddmAllocation; } delete gmm; return nullptr; } GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory(size_t size, size_t alignment, bool forcePin, bool uncacheable) { size_t newAlignment = alignment ? alignUp(alignment, MemoryConstants::pageSize) : MemoryConstants::pageSize; size_t sizeAligned = size ? alignUp(size, MemoryConstants::pageSize) : MemoryConstants::pageSize; void *pSysMem = allocateSystemMemory(sizeAligned, newAlignment); bool success = true; Gmm *gmm = nullptr; if (pSysMem == nullptr) { return nullptr; } WddmAllocation allocation(pSysMem, sizeAligned, pSysMem, sizeAligned); allocation.cpuPtrAllocated = true; gmm = Gmm::create(pSysMem, sizeAligned, uncacheable); while (success) { allocation.gmm = gmm; success = wddm->createAllocation(&allocation) == STATUS_SUCCESS; if (!success) break; auto *wddmAllocation = new WddmAllocation(allocation); return wddmAllocation; } delete gmm; freeSystemMemory(pSysMem); return nullptr; } GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory(size_t size, const void *ptrArg) { void *ptr = const_cast(ptrArg); if (ptr == nullptr) { DEBUG_BREAK_IF(true); return nullptr; } return MemoryManager::allocateGraphicsMemory(size, ptr); } GraphicsAllocation *WddmMemoryManager::allocate32BitGraphicsMemory(size_t size, void *ptr) { GraphicsAllocation *graphicsAllocation = nullptr; bool success = true; Gmm *gmm = nullptr; const void *ptrAligned = nullptr; size_t sizeAligned = size; void *pSysMem = nullptr; size_t offset = 0; bool cpuPtrAllocated = false; if (ptr) { ptrAligned = alignDown(ptr, MemoryConstants::allocationAlignment); sizeAligned = alignSizeWholePage(ptr, size); offset = ptrDiff(ptr, ptrAligned); } else { sizeAligned = alignUp(size, MemoryConstants::allocationAlignment); pSysMem = allocateSystemMemory(sizeAligned, MemoryConstants::allocationAlignment); if (pSysMem == nullptr) { return nullptr; } ptrAligned = pSysMem; cpuPtrAllocated = true; } WddmAllocation allocation((void *)ptrAligned, sizeAligned, (void *)ptrAligned, sizeAligned); allocation.cpuPtrAllocated = cpuPtrAllocated; allocation.is32BitAllocation = true; gmm = Gmm::create(ptrAligned, sizeAligned, false); while (success) { allocation.gmm = gmm; success = wddm->createAllocation(&allocation) == STATUS_SUCCESS; if (!success) break; allocation.setGpuAddress(allocation.gpuPtr); allocation.allocationOffset = offset; auto *wddmAllocation = new WddmAllocation(allocation); graphicsAllocation = wddmAllocation; graphicsAllocation->is32BitAllocation = true; graphicsAllocation->gpuBaseAddress = Gmm::canonize(allocator32Bit->getBase()); return graphicsAllocation; } delete gmm; freeSystemMemory(pSysMem); return nullptr; } GraphicsAllocation *WddmMemoryManager::createAllocationFromHandle(osHandle handle, bool requireSpecificBitness, bool ntHandle) { WddmAllocation allocation(nullptr, 0, handle); bool is32BitAllocation = false; if (ntHandle) { wddm->openNTHandle((HANDLE)((UINT_PTR)handle), &allocation); } else { if (wddm->openSharedHandle(handle, &allocation) == false) { return nullptr; } } // Shared objects are passed without size size_t size = allocation.gmm->gmmResourceInfo->getSizeAllocation(); allocation.setSize(size); void *ptr = nullptr; if (is32bit) { ptr = (void *)VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); } else if (requireSpecificBitness && this->force32bitAllocations) { is32BitAllocation = true; allocation.is32BitAllocation = true; allocation.gpuBaseAddress = Gmm::canonize(allocator32Bit->getBase()); } wddm->mapGpuVirtualAddress(&allocation, ptr, size, is32BitAllocation, false); allocation.setGpuAddress(allocation.gpuPtr); return new WddmAllocation(allocation); } GraphicsAllocation *WddmMemoryManager::createGraphicsAllocationFromSharedHandle(osHandle handle, bool requireSpecificBitness, bool /*isReused*/) { return createAllocationFromHandle(handle, requireSpecificBitness, false); } GraphicsAllocation *WddmMemoryManager::createGraphicsAllocationFromNTHandle(void *handle) { return createAllocationFromHandle((osHandle)((UINT_PTR)handle), false, true); } void *WddmMemoryManager::lockResource(GraphicsAllocation *graphicsAllocation) { return wddm->lockResource(static_cast(graphicsAllocation)); }; void WddmMemoryManager::unlockResource(GraphicsAllocation *graphicsAllocation) { wddm->unlockResource(static_cast(graphicsAllocation)); }; void WddmMemoryManager::freeGraphicsMemoryImpl(GraphicsAllocation *gfxAllocation) { WddmAllocation *input = static_cast(gfxAllocation); auto status = validateAllocation(input); DEBUG_BREAK_IF(!status); acquireResidencyLock(); if (input->getTrimCandidateListPosition() != trimListUnusedPosition) { removeFromTrimCandidateList(gfxAllocation, true); } releaseResidencyLock(); if (input->gmm) { if (input->gmm->isRenderCompressed) { status = unmapAuxVA(input->gmm, input->gpuPtr); DEBUG_BREAK_IF(!status); } delete input->gmm; } if (input->peekSharedHandle() == false && input->cpuPtrAllocated == false && input->fragmentsStorage.fragmentCount > 0) { cleanGraphicsMemoryCreatedFromHostPtr(gfxAllocation); } else { D3DKMT_HANDLE *allocationHandles = nullptr; uint32_t allocationCount = 0; D3DKMT_HANDLE resourceHandle = 0; void *cpuPtr = nullptr; void *gpuPtr = nullptr; if (input->peekSharedHandle()) { resourceHandle = input->resourceHandle; if (is32bit) { gpuPtr = (void *)input->gpuPtr; } } else { allocationHandles = &input->handle; allocationCount = 1; if (input->cpuPtrAllocated) { cpuPtr = input->getAlignedCpuPtr(); } } if (input->isLocked()) { unlockResource(input); input->setLocked(false); } status = tryDeferDeletions(allocationHandles, allocationCount, input->getResidencyData().lastFence, resourceHandle, cpuPtr, gpuPtr); DEBUG_BREAK_IF(!status); } delete gfxAllocation; } bool WddmMemoryManager::tryDeferDeletions(D3DKMT_HANDLE *handles, uint32_t allocationCount, uint64_t lastFenceValue, D3DKMT_HANDLE resourceHandle, void *cpuPtr, void *gpuPtr) { bool status = true; if (deferredDeleter) { deferredDeleter->deferDeletion(DeferrableDeletion::create(wddm, handles, allocationCount, lastFenceValue, resourceHandle, cpuPtr, gpuPtr)); } else { status = wddm->destroyAllocations(handles, allocationCount, lastFenceValue, resourceHandle); ::alignedFree(cpuPtr); wddm->releaseGpuPtr(gpuPtr); } return status; } bool WddmMemoryManager::validateAllocation(WddmAllocation *alloc) { if (alloc == nullptr) return false; auto size = alloc->getUnderlyingBufferSize(); if (alloc->getGpuAddress() == 0u || size == 0 || (alloc->handle == 0 && alloc->fragmentsStorage.fragmentCount == 0)) return false; return true; } bool WddmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { for (unsigned int i = 0; i < max_fragments_count; i++) { // If no fragment is present it means it already exists. if (!handleStorage.fragmentStorageData[i].osHandleStorage && handleStorage.fragmentStorageData[i].cpuPtr) { handleStorage.fragmentStorageData[i].osHandleStorage = new OsHandle(); handleStorage.fragmentStorageData[i].residency = new ResidencyData(); handleStorage.fragmentStorageData[i].osHandleStorage->gmm = Gmm::create(handleStorage.fragmentStorageData[i].cpuPtr, handleStorage.fragmentStorageData[i].fragmentSize, false); hostPtrManager.storeFragment(handleStorage.fragmentStorageData[i]); } } wddm->createAllocationsAndMapGpuVa(handleStorage); return true; } void WddmMemoryManager::cleanOsHandles(OsHandleStorage &handleStorage) { D3DKMT_HANDLE handles[max_fragments_count] = {0}; auto allocationCount = 0; uint64_t lastFenceValue = 0; for (unsigned int i = 0; i < max_fragments_count; i++) { if (handleStorage.fragmentStorageData[i].freeTheFragment) { handles[allocationCount] = handleStorage.fragmentStorageData[i].osHandleStorage->handle; handleStorage.fragmentStorageData[i].residency->resident = false; allocationCount++; lastFenceValue = std::max(handleStorage.fragmentStorageData[i].residency->lastFence, lastFenceValue); } } bool success = tryDeferDeletions(handles, allocationCount, lastFenceValue, 0, nullptr, nullptr); for (unsigned int i = 0; i < max_fragments_count; i++) { if (handleStorage.fragmentStorageData[i].freeTheFragment) { if (success) { handleStorage.fragmentStorageData[i].osHandleStorage->handle = 0; } delete handleStorage.fragmentStorageData[i].osHandleStorage->gmm; delete handleStorage.fragmentStorageData[i].osHandleStorage; delete handleStorage.fragmentStorageData[i].residency; } } } GraphicsAllocation *WddmMemoryManager::createGraphicsAllocation(OsHandleStorage &handleStorage, size_t hostPtrSize, const void *hostPtr) { auto allocation = new WddmAllocation(const_cast(hostPtr), hostPtrSize, const_cast(hostPtr), hostPtrSize); allocation->fragmentsStorage = handleStorage; return allocation; } uint64_t WddmMemoryManager::getSystemSharedMemory() { return wddm->getSystemSharedMemory(); } uint64_t WddmMemoryManager::getMaxApplicationAddress() { return wddm->getMaxApplicationAddress(); } bool WddmMemoryManager::makeResidentResidencyAllocations(ResidencyContainer *allocationsForResidency) { auto &residencyAllocations = allocationsForResidency ? *allocationsForResidency : this->residencyAllocations; size_t residencyCount = residencyAllocations.size(); std::unique_ptr handlesForResidency(new D3DKMT_HANDLE[residencyCount * max_fragments_count]); uint32_t totalHandlesCount = 0; acquireResidencyLock(); DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "currentFenceValue =", wddm->getMonitoredFence().currentFenceValue); for (uint32_t i = 0; i < residencyCount; i++) { WddmAllocation *allocation = reinterpret_cast(residencyAllocations[i]); bool mainResidency = false; bool fragmentResidency[3] = {false, false, false}; mainResidency = allocation->getResidencyData().resident; DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "allocation =", allocation, mainResidency ? "resident" : "not resident"); if (allocation->getTrimCandidateListPosition() != trimListUnusedPosition) { DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "allocation =", allocation, "on trimCandidateList"); removeFromTrimCandidateList(allocation); } else { for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) { fragmentResidency[allocationId] = allocation->fragmentsStorage.fragmentStorageData[allocationId].residency->resident; DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "fragment handle =", allocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage->handle, fragmentResidency[allocationId] ? "resident" : "not resident"); } } if (allocation->fragmentsStorage.fragmentCount == 0) { if (!mainResidency) handlesForResidency[totalHandlesCount++] = allocation->handle; } else { for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) { if (!fragmentResidency[allocationId]) handlesForResidency[totalHandlesCount++] = allocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage->handle; } } } bool result = true; if (totalHandlesCount) { uint64_t bytesToTrim = 0; while ((result = wddm->makeResident(handlesForResidency.get(), totalHandlesCount, false, &bytesToTrim)) == false) { this->memoryBudgetExhausted = true; bool trimmingDone = trimResidencyToBudget(bytesToTrim); bool cantTrimFurther = !trimmingDone; if (cantTrimFurther) { result = wddm->makeResident(handlesForResidency.get(), totalHandlesCount, true, &bytesToTrim); break; } } } if (result == true) { for (uint32_t i = 0; i < residencyCount; i++) { WddmAllocation *allocation = reinterpret_cast(residencyAllocations[i]); // Update fence value not to early destroy / evict allocation allocation->getResidencyData().lastFence = wddm->getMonitoredFence().currentFenceValue; allocation->getResidencyData().resident = true; for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) { allocation->fragmentsStorage.fragmentStorageData[allocationId].residency->resident = true; // Update fence value not to remove the fragment referenced by different GA in trimming callback allocation->fragmentsStorage.fragmentStorageData[allocationId].residency->lastFence = wddm->getMonitoredFence().currentFenceValue; } } } releaseResidencyLock(); return result; } void WddmMemoryManager::makeNonResidentEvictionAllocations() { acquireResidencyLock(); size_t residencyCount = evictionAllocations.size(); for (uint32_t i = 0; i < residencyCount; i++) { WddmAllocation *allocation = reinterpret_cast(evictionAllocations[i]); addToTrimCandidateList(allocation); } releaseResidencyLock(); } void WddmMemoryManager::removeFromTrimCandidateList(GraphicsAllocation *allocation, bool compactList) { WddmAllocation *wddmAllocation = (WddmAllocation *)allocation; size_t position = wddmAllocation->getTrimCandidateListPosition(); DEBUG_BREAK_IF(!(trimCandidatesCount > (trimCandidatesCount - 1))); DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size()); trimCandidatesCount--; trimCandidateList[position] = nullptr; checkTrimCandidateCount(); if (position == trimCandidateList.size() - 1) { size_t erasePosition = position; if (position == 0) { trimCandidateList.resize(0); } else { while (trimCandidateList[erasePosition] == nullptr && erasePosition > 0) { erasePosition--; } size_t sizeRemaining = erasePosition + 1; if (erasePosition == 0 && trimCandidateList[erasePosition] == nullptr) { sizeRemaining = 0; } trimCandidateList.resize(sizeRemaining); } } wddmAllocation->setTrimCandidateListPosition(trimListUnusedPosition); if (compactList && checkTrimCandidateListCompaction()) { compactTrimCandidateList(); } checkTrimCandidateCount(); } void WddmMemoryManager::addToTrimCandidateList(GraphicsAllocation *allocation) { WddmAllocation *wddmAllocation = (WddmAllocation *)allocation; size_t position = trimCandidateList.size(); DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size()); if (wddmAllocation->getTrimCandidateListPosition() == trimListUnusedPosition) { trimCandidatesCount++; trimCandidateList.push_back(allocation); wddmAllocation->setTrimCandidateListPosition(position); } checkTrimCandidateCount(); } void WddmMemoryManager::compactTrimCandidateList() { size_t size = trimCandidateList.size(); size_t freePosition = 0; if (size == 0 || size == trimCandidatesCount) { return; } DEBUG_BREAK_IF(!(trimCandidateList[size - 1] != nullptr)); uint32_t previousCount = trimCandidatesCount; DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size()); while (freePosition < trimCandidatesCount && trimCandidateList[freePosition] != nullptr) freePosition++; for (uint32_t i = 1; i < size; i++) { if (trimCandidateList[i] != nullptr && freePosition < i) { trimCandidateList[freePosition] = trimCandidateList[i]; trimCandidateList[i] = nullptr; ((WddmAllocation *)trimCandidateList[freePosition])->setTrimCandidateListPosition(freePosition); freePosition++; // Last element was moved, erase elements from freePosition if (i == size - 1) { trimCandidateList.resize(freePosition); } } } DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size()); DEBUG_BREAK_IF(trimCandidatesCount != previousCount); checkTrimCandidateCount(); } void WddmMemoryManager::trimResidency(D3DDDI_TRIMRESIDENCYSET_FLAGS flags, uint64_t bytes) { if (flags.PeriodicTrim) { bool periodicTrimDone = false; D3DKMT_HANDLE fragmentEvictHandles[3] = {0}; uint64_t sizeToTrim = 0; acquireResidencyLock(); size_t size = trimCandidateList.size(); WddmAllocation *wddmAllocation = nullptr; while ((wddmAllocation = getTrimCandidateHead()) != nullptr) { DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "lastPeriodicTrimFenceValue = ", lastPeriodicTrimFenceValue); // allocation was not used from last periodic trim if ((wddmAllocation)->getResidencyData().lastFence <= lastPeriodicTrimFenceValue) { DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "allocation: handle =", wddmAllocation->handle, "lastFence =", (wddmAllocation)->getResidencyData().lastFence); size_t fragmentsSizeToEvict = 0; uint32_t fragmentsToEvict = 0; if (wddmAllocation->fragmentsStorage.fragmentCount == 0) { DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "Evict allocation: handle =", wddmAllocation->handle, "lastFence =", (wddmAllocation)->getResidencyData().lastFence); wddm->evict(&wddmAllocation->handle, 1, sizeToTrim); } for (uint32_t allocationId = 0; allocationId < wddmAllocation->fragmentsStorage.fragmentCount; allocationId++) { if (wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->lastFence <= lastPeriodicTrimFenceValue) { DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "Evict fragment: handle =", wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage->handle, "lastFence =", wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->lastFence); fragmentEvictHandles[fragmentsToEvict++] = wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage->handle; wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->resident = false; } } if (fragmentsToEvict != 0) { wddm->evict((D3DKMT_HANDLE *)fragmentEvictHandles, fragmentsToEvict, sizeToTrim); } wddmAllocation->getResidencyData().resident = false; removeFromTrimCandidateList(wddmAllocation); } else { periodicTrimDone = true; break; } } if (checkTrimCandidateListCompaction()) { compactTrimCandidateList(); } releaseResidencyLock(); } if (flags.TrimToBudget) { acquireResidencyLock(); trimResidencyToBudget(bytes); releaseResidencyLock(); } if (flags.PeriodicTrim || flags.RestartPeriodicTrim) { lastPeriodicTrimFenceValue = *wddm->getMonitoredFence().cpuAddress; DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "updated lastPeriodicTrimFenceValue =", lastPeriodicTrimFenceValue); } } void WddmMemoryManager::checkTrimCandidateCount() { if (DebugManager.flags.ResidencyDebugEnable.get()) { uint32_t sum = 0; for (size_t i = 0; i < trimCandidateList.size(); i++) { if (trimCandidateList[i] != nullptr) { sum++; } } DEBUG_BREAK_IF(sum != trimCandidatesCount); } } bool WddmMemoryManager::checkTrimCandidateListCompaction() { if (2 * trimCandidatesCount <= trimCandidateList.size()) { return true; } return false; } bool WddmMemoryManager::trimResidencyToBudget(uint64_t bytes) { bool trimToBudgetDone = false; D3DKMT_HANDLE fragmentEvictHandles[3] = {0}; uint64_t numberOfBytesToTrim = bytes; WddmAllocation *wddmAllocation = nullptr; trimToBudgetDone = (numberOfBytesToTrim == 0); while (!trimToBudgetDone) { uint64_t lastFence = 0; wddmAllocation = getTrimCandidateHead(); if (wddmAllocation == nullptr) { break; } lastFence = wddmAllocation->getResidencyData().lastFence; if (lastFence <= wddm->getMonitoredFence().lastSubmittedFence) { uint32_t fragmentsToEvict = 0; uint64_t sizeEvicted = 0; uint64_t sizeToTrim = 0; if (lastFence > *wddm->getMonitoredFence().cpuAddress) { wddm->waitFromCpu(lastFence); } if (wddmAllocation->fragmentsStorage.fragmentCount == 0) { wddm->evict(&wddmAllocation->handle, 1, sizeToTrim); sizeEvicted = wddmAllocation->getUnderlyingBufferSize(); } else { for (uint32_t allocationId = 0; allocationId < wddmAllocation->fragmentsStorage.fragmentCount; allocationId++) { if (wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->lastFence <= wddm->getMonitoredFence().lastSubmittedFence) { fragmentEvictHandles[fragmentsToEvict++] = wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage->handle; } } if (fragmentsToEvict != 0) { wddm->evict((D3DKMT_HANDLE *)fragmentEvictHandles, fragmentsToEvict, sizeToTrim); for (uint32_t allocationId = 0; allocationId < wddmAllocation->fragmentsStorage.fragmentCount; allocationId++) { if (wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->lastFence <= wddm->getMonitoredFence().lastSubmittedFence) { wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].residency->resident = false; sizeEvicted += wddmAllocation->fragmentsStorage.fragmentStorageData[allocationId].fragmentSize; } } } } if (sizeEvicted >= numberOfBytesToTrim) { numberOfBytesToTrim = 0; } else { numberOfBytesToTrim -= sizeEvicted; } wddmAllocation->getResidencyData().resident = false; removeFromTrimCandidateList(wddmAllocation); trimToBudgetDone = (numberOfBytesToTrim == 0); } else { trimToBudgetDone = true; } } if (bytes > numberOfBytesToTrim && checkTrimCandidateListCompaction()) { compactTrimCandidateList(); } return numberOfBytesToTrim == 0; } bool WddmMemoryManager::unmapAuxVA(Gmm *gmm, D3DGPU_VIRTUAL_ADDRESS &gpuVA) { GMM_DDI_UPDATEAUXTABLE ddiUpdateAuxTable = {}; ddiUpdateAuxTable.BaseGpuVA = gpuVA; ddiUpdateAuxTable.BaseResInfo = gmm->gmmResourceInfo->peekHandle(); ddiUpdateAuxTable.DoNotWait = true; ddiUpdateAuxTable.Map = false; return wddm->updateAuxTable(ddiUpdateAuxTable); } } // namespace OCLRT