/* * Copyright (C) 2018-2025 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/gmm_helper/gmm_helper.h" #include "shared/source/os_interface/windows/driver_info_windows.h" #include "shared/source/os_interface/windows/dxgi_wrapper.h" #include "shared/source/os_interface/windows/wddm/um_km_data_translator.h" #include "shared/source/os_interface/windows/wddm_engine_mapper.h" #include "shared/source/os_interface/windows/wddm_memory_manager.h" #include "shared/source/utilities/debug_settings_reader.h" #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/mocks/mock_gfx_partition.h" #include "shared/test/common/mocks/mock_gmm_resource_info.h" #include "shared/test/common/mocks/mock_io_functions.h" #include "shared/test/common/mocks/mock_memory_manager.h" #include "shared/test/common/mocks/mock_wddm_residency_logger.h" #include "shared/test/common/mocks/windows/mock_gdi_interface.h" #include "shared/test/common/mocks/windows/mock_gmm_memory_base.h" #include "shared/test/common/mocks/windows/mock_wddm_allocation.h" #include "shared/test/common/os_interface/windows/ult_dxcore_factory.h" #include "shared/test/common/os_interface/windows/wddm_fixture.h" #include "shared/test/common/test_macros/hw_test.h" namespace NEO { namespace SysCalls { extern const wchar_t *currentLibraryPath; } extern uint32_t numRootDevicesToEnum; std::unique_ptr createHwDeviceIdFromAdapterLuid(OsEnvironmentWin &osEnvironment, LUID adapterLuid, uint32_t adapterNodeOrdinalIn); } // namespace NEO using namespace NEO; namespace GmmHelperFunctions { Gmm *getGmm(void *ptr, size_t size, GmmHelper *gmmHelper) { size_t alignedSize = alignSizeWholePage(ptr, size); void *alignedPtr = alignUp(ptr, 4096); GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; Gmm *gmm = new Gmm(gmmHelper, alignedPtr, alignedSize, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); EXPECT_NE(gmm->gmmResourceInfo.get(), nullptr); return gmm; } } // namespace GmmHelperFunctions using Wddm20Tests = WddmTest; using Wddm20WithMockGdiDllTestsWithoutWddmInit = WddmTestWithMockGdiDll; using Wddm20InstrumentationTest = WddmInstrumentationTest; struct Wddm20WithMockGdiDllTests : public Wddm20WithMockGdiDllTestsWithoutWddmInit { using Wddm20WithMockGdiDllTestsWithoutWddmInit::TearDown; void SetUp() override { Wddm20WithMockGdiDllTestsWithoutWddmInit::SetUp(); init(); } }; TEST_F(Wddm20Tests, givenMinWindowsAddressWhenWddmIsInitializedThenWddmUseThisAddress) { uintptr_t expectedAddress = 0x200000; EXPECT_EQ(expectedAddress, NEO::windowsMinAddress); EXPECT_EQ(expectedAddress, wddm->getWddmMinAddress()); } TEST_F(Wddm20Tests, GivenExisitingContextWhenInitializingWddmThenCreateContextResultCalledIsStillOne) { EXPECT_EQ(1u, wddm->createContextResult.called); wddm->init(); EXPECT_EQ(1u, wddm->createContextResult.called); } TEST_F(Wddm20Tests, givenNullPageTableManagerAndCompressedResourceWhenMappingGpuVaThenDontUpdateAuxTable) { GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; auto gmm = std::unique_ptr(new Gmm(getGmmHelper(), nullptr, 1, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements)); auto mockGmmRes = reinterpret_cast(gmm->gmmResourceInfo.get()); mockGmmRes->setUnifiedAuxTranslationCapable(); void *fakePtr = reinterpret_cast(0x100); auto gmmHelper = getGmmHelper(); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(fakePtr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, fakePtr, canonizedAddress, 0x2100, nullptr, MemoryPool::memoryNull, 0u, 1u); allocation.setDefaultGmm(gmm.get()); allocation.getHandleToModify(0u) = ALLOCATION_HANDLE; EXPECT_TRUE(wddm->mapGpuVirtualAddress(&allocation)); } TEST(WddmDiscoverDevices, WhenNoHwDeviceIdIsProvidedToWddmThenWddmIsNotCreated) { struct MockWddm : public Wddm { MockWddm(std::unique_ptr &&hwDeviceIdIn, RootDeviceEnvironment &rootDeviceEnvironment) : Wddm(std::move(hwDeviceIdIn), rootDeviceEnvironment) {} }; MockExecutionEnvironment executionEnvironment; RootDeviceEnvironment rootDeviceEnvironment(executionEnvironment); EXPECT_THROW(auto wddm = std::make_unique(nullptr, rootDeviceEnvironment), std::exception); } TEST(WddmDiscoverDevices, givenMultipleRootDevicesExposedWhenCreateMultipleRootDevicesFlagIsSetToLowerValueThenDiscoverOnlySpecifiedNumberOfDevices) { DebugManagerStateRestore restorer{}; VariableBackup backup{&numRootDevicesToEnum}; numRootDevicesToEnum = 3u; uint32_t requestedNumRootDevices = 2u; debugManager.flags.CreateMultipleRootDevices.set(requestedNumRootDevices); ExecutionEnvironment executionEnvironment; auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment); EXPECT_EQ(requestedNumRootDevices, hwDeviceIds.size()); } TEST(WddmDiscoverDevices, givenInvalidFirstAdapterWhenDiscoveringAdaptersThenReturnAllValidAdapters) { VariableBackup backup{&numRootDevicesToEnum, 2u}; VariableBackup backup2{&UltDXCoreAdapterList::firstInvalid, true}; ExecutionEnvironment executionEnvironment; auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment); EXPECT_EQ(1u, hwDeviceIds.size()); } TEST(WddmDiscoverDevices, givenMultipleRootDevicesExposedWhenCreateMultipleRootDevicesFlagIsSetToGreaterValueThenDiscoverSpecifiedNumberOfDevices) { DebugManagerStateRestore restorer{}; VariableBackup backup{&numRootDevicesToEnum}; numRootDevicesToEnum = 3u; uint32_t requestedNumRootDevices = 4u; debugManager.flags.CreateMultipleRootDevices.set(requestedNumRootDevices); ExecutionEnvironment executionEnvironment; auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment); EXPECT_EQ(requestedNumRootDevices, hwDeviceIds.size()); } TEST(WddmDiscoverDevices, WhenAdapterDescriptionContainsVirtualRenderThenAdapterIsDiscovered) { VariableBackup descriptionBackup(&UltDxCoreAdapter::description); descriptionBackup = "Virtual Render"; ExecutionEnvironment executionEnvironment; auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment); EXPECT_EQ(1u, hwDeviceIds.size()); EXPECT_NE(nullptr, hwDeviceIds[0].get()); } TEST(Wddm20EnumAdaptersTest, WhenInitializingWddmThenHardwareInfoIsCorrectlyPopulated) { const HardwareInfo *hwInfo = defaultHwInfo.get(); std::unique_ptr mockGdiDll(setAdapterInfo(&hwInfo->platform, &hwInfo->gtSystemInfo, hwInfo->capabilityTable.gpuAddressSpace)); MockExecutionEnvironment executionEnvironment; RootDeviceEnvironment rootDeviceEnvironment(executionEnvironment); auto wddm = Wddm::createWddm(nullptr, rootDeviceEnvironment); bool success = wddm->init(); EXPECT_TRUE(success); EXPECT_EQ(rootDeviceEnvironment.getHardwareInfo()->platform.eDisplayCoreFamily, hwInfo->platform.eDisplayCoreFamily); } TEST(Wddm20EnumAdaptersTest, givenUnknownPlatformWhenEnumAdapterIsCalledThenFalseIsReturnedAndOutputIsEmpty) { HardwareInfo hwInfo = *defaultHwInfo; hwInfo.platform.eProductFamily = IGFX_UNKNOWN; std::unique_ptr mockGdiDll(setAdapterInfo(&hwInfo.platform, &hwInfo.gtSystemInfo, hwInfo.capabilityTable.gpuAddressSpace)); MockExecutionEnvironment executionEnvironment; RootDeviceEnvironment rootDeviceEnvironment(executionEnvironment); auto wddm = Wddm::createWddm(nullptr, rootDeviceEnvironment); auto ret = wddm->init(); EXPECT_FALSE(ret); // reset mock gdi hwInfo = *defaultHwInfo; mockGdiDll.reset(setAdapterInfo(&hwInfo.platform, &hwInfo.gtSystemInfo, hwInfo.capabilityTable.gpuAddressSpace)); } TEST_F(Wddm20Tests, whenInitializeWddmThenContextIsCreated) { auto context = osContext->getWddmContextHandle(); EXPECT_TRUE(context != static_cast(0)); } TEST_F(Wddm20Tests, whenCreatingContextWithPowerHintSuccessIsReturned) { auto newContext = osContext.get(); newContext->setUmdPowerHintValue(1); EXPECT_EQ(1, newContext->getUmdPowerHintValue()); wddm->createContext(*newContext); EXPECT_TRUE(wddm->createContext(*newContext)); } TEST_F(Wddm20Tests, whenInitPrivateDataThenDefaultValuesAreSet) { auto newContext = osContext.get(); CREATECONTEXT_PVTDATA privateData = initPrivateData(*newContext); EXPECT_FALSE(privateData.IsProtectedProcess); EXPECT_FALSE(privateData.IsDwm); EXPECT_TRUE(privateData.GpuVAContext); EXPECT_FALSE(privateData.IsMediaUsage); } TEST_F(Wddm20Tests, WhenCreatingAllocationAndDestroyingAllocationThenCorrectResultReturned) { OsAgnosticMemoryManager mm(*executionEnvironment); auto gmmHelper = getGmmHelper(); auto ptr = mm.allocateSystemMemory(100, 0); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(ptr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, ptr, canonizedAddress, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); Gmm *gmm = GmmHelperFunctions::getGmm(allocation.getUnderlyingBuffer(), allocation.getUnderlyingBufferSize(), getGmmHelper()); allocation.setDefaultGmm(gmm); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.getDefaultHandle() != 0); auto error = wddm->destroyAllocation(&allocation, osContext.get()); EXPECT_TRUE(error); delete gmm; mm.freeSystemMemory(allocation.getUnderlyingBuffer()); } TEST_F(Wddm20WithMockGdiDllTests, givenAllocationSmallerUnderlyingThanAlignedSizeWhenCreatedThenWddmUseAligned) { void *ptr = reinterpret_cast(wddm->virtualAllocAddress + 0x1000); size_t underlyingSize = 0x2100; size_t alignedSize = 0x3000; size_t underlyingPages = underlyingSize / MemoryConstants::pageSize; size_t alignedPages = alignedSize / MemoryConstants::pageSize; auto gmmHelper = getGmmHelper(); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(ptr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, ptr, canonizedAddress, 0x2100, nullptr, MemoryPool::memoryNull, 0u, 1u); Gmm *gmm = GmmHelperFunctions::getGmm(allocation.getAlignedCpuPtr(), allocation.getAlignedSize(), getGmmHelper()); allocation.setDefaultGmm(gmm); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_NE(0u, allocation.getDefaultHandle()); bool ret = wddm->mapGpuVirtualAddress(&allocation); EXPECT_TRUE(ret); EXPECT_EQ(alignedPages, getLastCallMapGpuVaArgFcn()->SizeInPages); EXPECT_NE(underlyingPages, getLastCallMapGpuVaArgFcn()->SizeInPages); ret = wddm->destroyAllocation(&allocation, osContext.get()); EXPECT_TRUE(ret); delete gmm; } TEST_F(Wddm20WithMockGdiDllTests, givenReserveCallWhenItIsCalledWithProperParamtersThenAddressInRangeIsReturend) { auto sizeAlignedTo64Kb = 64 * MemoryConstants::kiloByte; D3DGPU_VIRTUAL_ADDRESS reservationAddress; auto status = wddm->reserveGpuVirtualAddress(0ull, wddm->getGfxPartition().Heap32[0].Base, wddm->getGfxPartition().Heap32[0].Limit, sizeAlignedTo64Kb, &reservationAddress); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_GE(reservationAddress, wddm->getGfxPartition().Heap32[0].Base); auto programmedReserved = getLastCallReserveGpuVaArgFcn(); EXPECT_EQ(0llu, programmedReserved->BaseAddress); EXPECT_EQ(wddm->getGfxPartition().Heap32[0].Base, programmedReserved->MinimumAddress); EXPECT_EQ(wddm->getGfxPartition().Heap32[0].Limit, programmedReserved->MaximumAddress); EXPECT_EQ(sizeAlignedTo64Kb, programmedReserved->Size); auto pagingQueue = wddm->getPagingQueue(); EXPECT_NE(0llu, pagingQueue); EXPECT_EQ(pagingQueue, programmedReserved->hPagingQueue); } TEST_F(Wddm20WithMockGdiDllTests, givenReserveCallWhenItIsCalledWithInvalidBaseThenFailureIsReturned) { auto sizeAlignedTo64Kb = 64 * MemoryConstants::kiloByte; D3DGPU_VIRTUAL_ADDRESS reservationAddress; auto status = wddm->reserveGpuVirtualAddress(0x1234, wddm->getGfxPartition().Heap32[0].Base, wddm->getGfxPartition().Heap32[0].Limit, sizeAlignedTo64Kb, &reservationAddress); EXPECT_NE(STATUS_SUCCESS, status); } TEST_F(Wddm20WithMockGdiDllTests, givenReserveCallWhenItIsCalledWithAttemptBaseAddressWithValidBaseThenAddressInRangeIsReturned) { auto sizeAlignedTo64Kb = 64 * MemoryConstants::kiloByte; D3DGPU_VIRTUAL_ADDRESS previousReservationAddress; D3DGPU_VIRTUAL_ADDRESS reservationAddress; NTSTATUS status; status = wddm->reserveGpuVirtualAddress(0ull, wddm->getGfxPartition().Heap32[0].Base, wddm->getGfxPartition().Heap32[0].Limit, sizeAlignedTo64Kb, &previousReservationAddress); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(wddm->freeGpuVirtualAddress(previousReservationAddress, sizeAlignedTo64Kb)); status = wddm->reserveGpuVirtualAddress(previousReservationAddress, wddm->getGfxPartition().Heap32[0].Base, wddm->getGfxPartition().Heap32[0].Limit, sizeAlignedTo64Kb, &reservationAddress); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_GE(reservationAddress, wddm->getGfxPartition().Heap32[0].Base); auto programmedReserved = getLastCallReserveGpuVaArgFcn(); EXPECT_EQ(0llu, programmedReserved->BaseAddress); EXPECT_EQ(wddm->getGfxPartition().Heap32[0].Base, programmedReserved->MinimumAddress); EXPECT_EQ(wddm->getGfxPartition().Heap32[0].Limit, programmedReserved->MaximumAddress); EXPECT_EQ(sizeAlignedTo64Kb, programmedReserved->Size); auto pagingQueue = wddm->getPagingQueue(); EXPECT_NE(0llu, pagingQueue); EXPECT_EQ(pagingQueue, programmedReserved->hPagingQueue); } TEST_F(Wddm20WithMockGdiDllTests, givenWddmAllocationWhenMappingGpuVaThenUseGmmSize) { void *fakePtr = reinterpret_cast(0x123); auto gmmHelper = getGmmHelper(); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(fakePtr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, fakePtr, canonizedAddress, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); std::unique_ptr gmm(GmmHelperFunctions::getGmm(allocation.getAlignedCpuPtr(), allocation.getAlignedSize(), getGmmHelper())); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); auto mockResourceInfo = static_cast(gmm->gmmResourceInfo.get()); mockResourceInfo->overrideReturnedSize(allocation.getAlignedSize() + (2 * MemoryConstants::pageSize)); wddm->mapGpuVirtualAddress(&allocation); uint64_t expectedSizeInPages = static_cast(mockResourceInfo->getSizeAllocation() / MemoryConstants::pageSize); EXPECT_EQ(expectedSizeInPages, getLastCallMapGpuVaArgFcn()->SizeInPages); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(Wddm20WithMockGdiDllTests, GivenInvalidCpuAddressWhenCheckingForGpuHangThenFalseIsReturned) { osContext->getResidencyController().getMonitoredFence().cpuAddress = nullptr; EXPECT_FALSE(wddm->isGpuHangDetected(*osContext)); } TEST_F(Wddm20WithMockGdiDllTests, GivenCpuValueDifferentThanGpuHangIndicationWhenCheckingForGpuHangThenFalseIsReturned) { constexpr auto cpuValue{777u}; ASSERT_NE(NEO::Wddm::gpuHangIndication, cpuValue); *osContext->getResidencyController().getMonitoredFence().cpuAddress = cpuValue; EXPECT_FALSE(wddm->isGpuHangDetected(*osContext)); } TEST_F(Wddm20WithMockGdiDllTests, whencreateMonitoredFenceForDirectSubmissionThenCreateFence) { MonitoredFence fence{}; wddm->getWddmInterface()->createFenceForDirectSubmission(fence, *osContext); EXPECT_EQ(wddmMockInterface->createMonitoredFenceCalled, 1u); EXPECT_NE(osContext->getHwQueue().progressFenceHandle, fence.fenceHandle); wddm->getWddmInterface()->destroyMonitorFence(fence); } TEST_F(Wddm20WithMockGdiDllTests, GivenGpuHangIndicationWhenCheckingForGpuHangThenTrueIsReturned) { auto fenceCpuAddress = osContext->getResidencyController().getMonitoredFence().cpuAddress; VariableBackup backupWddmMonitorFence(fenceCpuAddress); *fenceCpuAddress = NEO::Wddm::gpuHangIndication; EXPECT_TRUE(wddm->isGpuHangDetected(*osContext)); } TEST_F(Wddm20WithMockGdiDllTests, GivenThreeOsHandlesWhenAskedForDestroyAllocationsThenAllMarkedAllocationsAreDestroyed) { OsHandleStorage storage; OsHandleWin osHandle1; OsHandleWin osHandle2; OsHandleWin osHandle3; osHandle1.handle = ALLOCATION_HANDLE; osHandle2.handle = ALLOCATION_HANDLE; osHandle3.handle = ALLOCATION_HANDLE; storage.fragmentStorageData[0].osHandleStorage = &osHandle1; storage.fragmentStorageData[0].freeTheFragment = true; storage.fragmentStorageData[1].osHandleStorage = &osHandle2; storage.fragmentStorageData[1].freeTheFragment = false; storage.fragmentStorageData[2].osHandleStorage = &osHandle3; storage.fragmentStorageData[2].freeTheFragment = true; D3DKMT_HANDLE handles[3] = {ALLOCATION_HANDLE, ALLOCATION_HANDLE, ALLOCATION_HANDLE}; bool retVal = wddm->destroyAllocations(handles, 3, 0); EXPECT_TRUE(retVal); auto destroyWithResourceHandleCalled = 0u; D3DKMT_DESTROYALLOCATION2 *ptrToDestroyAlloc2 = nullptr; getSizesFcn(destroyWithResourceHandleCalled, ptrToDestroyAlloc2); EXPECT_EQ(0u, ptrToDestroyAlloc2->Flags.SynchronousDestroy); EXPECT_EQ(1u, ptrToDestroyAlloc2->Flags.AssumeNotInUse); } TEST_F(Wddm20WithMockGdiDllTests, GivenSetAssumeNotInUseSetToFalseWhenDestroyAllocationsThenAssumeNotInUseNotSet) { DebugManagerStateRestore restorer; debugManager.flags.SetAssumeNotInUse.set(false); OsHandleStorage storage; OsHandleWin osHandle1; osHandle1.handle = ALLOCATION_HANDLE; storage.fragmentStorageData[0].osHandleStorage = &osHandle1; storage.fragmentStorageData[0].freeTheFragment = true; D3DKMT_HANDLE handles[1] = {ALLOCATION_HANDLE}; bool retVal = wddm->destroyAllocations(handles, 1, 0); EXPECT_TRUE(retVal); auto destroyWithResourceHandleCalled = 0u; D3DKMT_DESTROYALLOCATION2 *ptrToDestroyAlloc2 = nullptr; getSizesFcn(destroyWithResourceHandleCalled, ptrToDestroyAlloc2); EXPECT_EQ(0u, ptrToDestroyAlloc2->Flags.AssumeNotInUse); } TEST_F(Wddm20Tests, WhenMappingAndFreeingGpuVaThenReturnIsCorrect) { OsAgnosticMemoryManager mm(*executionEnvironment); auto gmmHelper = getGmmHelper(); auto ptr = mm.allocateSystemMemory(100, 0); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(ptr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, ptr, canonizedAddress, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); Gmm *gmm = GmmHelperFunctions::getGmm(allocation.getUnderlyingBuffer(), allocation.getUnderlyingBufferSize(), getGmmHelper()); allocation.setDefaultGmm(gmm); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.getDefaultHandle() != 0); auto error = wddm->mapGpuVirtualAddress(&allocation); EXPECT_TRUE(error); EXPECT_TRUE(allocation.getGpuAddress() != 0); error = wddm->freeGpuVirtualAddress(allocation.getGpuAddressToModify(), allocation.getUnderlyingBufferSize()); EXPECT_TRUE(error); EXPECT_TRUE(allocation.getGpuAddress() == 0); error = wddm->destroyAllocation(&allocation, osContext.get()); EXPECT_TRUE(error); delete gmm; mm.freeSystemMemory(allocation.getUnderlyingBuffer()); } TEST_F(Wddm20Tests, givenNullAllocationWhenCreateThenAllocateAndMap) { WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(allocation.getUnderlyingBuffer(), allocation.getUnderlyingBufferSize(), getGmmHelper())); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); bool ret = wddm->mapGpuVirtualAddress(&allocation); EXPECT_TRUE(ret); EXPECT_NE(0u, allocation.getGpuAddress()); auto gmmHelper = rootDeviceEnvironment->getGmmHelper(); EXPECT_EQ(allocation.getGpuAddress(), gmmHelper->canonize(allocation.getGpuAddress())); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(WddmTestWithMockGdiDll, givenShareableAllocationWhenCreateThenCreateResourceFlagIsEnabled) { init(); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, MemoryConstants::pageSize, nullptr, MemoryPool::memoryNull, true, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(nullptr, MemoryConstants::pageSize, getGmmHelper())); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); auto passedCreateAllocation = getMockAllocationFcn(); EXPECT_EQ(1u, passedCreateAllocation->Flags.CreateShared); EXPECT_EQ(1u, passedCreateAllocation->Flags.CreateResource); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(WddmTestWithMockGdiDll, givenCompressedResourceWhenItIsCreatedThenItMayContainNonZeroContent) { DebugManagerStateRestore restorer; NEO::debugManager.flags.AllowNotZeroForCompressedOnWddm.set(1); init(); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, MemoryConstants::pageSize, nullptr, MemoryPool::memoryNull, true, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(nullptr, MemoryConstants::pageSize, getGmmHelper())); gmm->setCompressionEnabled(true); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); auto passedCreateAllocation = getMockAllocationFcn(); EXPECT_EQ(1u, passedCreateAllocation->Flags.AllowNotZeroed); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(WddmTestWithMockGdiDll, givenNonCompressedResourceWhenItIsCreatedThenItCannotContainNonZeroContent) { DebugManagerStateRestore restorer; NEO::debugManager.flags.AllowNotZeroForCompressedOnWddm.set(1); init(); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, MemoryConstants::pageSize, nullptr, MemoryPool::memoryNull, true, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(nullptr, MemoryConstants::pageSize, getGmmHelper())); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); auto passedCreateAllocation = getMockAllocationFcn(); EXPECT_EQ(0u, passedCreateAllocation->Flags.AllowNotZeroed); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(WddmTestWithMockGdiDll, givenCompressedResourceWhenItIsCreatedThenItCannotContainNonZeroContent) { init(); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, MemoryConstants::pageSize, nullptr, MemoryPool::memoryNull, true, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(nullptr, MemoryConstants::pageSize, getGmmHelper())); gmm->setCompressionEnabled(true); allocation.setDefaultGmm(gmm.get()); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); auto passedCreateAllocation = getMockAllocationFcn(); EXPECT_EQ(0u, passedCreateAllocation->Flags.AllowNotZeroed); wddm->destroyAllocation(&allocation, nullptr); } TEST_F(WddmTestWithMockGdiDll, givenShareableAllocationWhenCreateThenSharedHandleAndResourceHandleAreSet) { init(); struct MockWddmMemoryManager : public WddmMemoryManager { using WddmMemoryManager::createGpuAllocationsWithRetry; using WddmMemoryManager::WddmMemoryManager; }; MemoryManagerCreate memoryManager(false, false, *executionEnvironment); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, nullptr, 0, MemoryConstants::pageSize, nullptr, MemoryPool::memoryNull, true, 1u); auto gmm = std::unique_ptr(GmmHelperFunctions::getGmm(nullptr, MemoryConstants::pageSize, getGmmHelper())); allocation.setDefaultGmm(gmm.get()); auto status = memoryManager.createGpuAllocationsWithRetry(&allocation); EXPECT_TRUE(status); uint64_t handle = 0; allocation.peekInternalHandle(&memoryManager, handle); EXPECT_NE(0u, handle); } TEST_F(Wddm20Tests, WhenMakingResidentAndEvictingThenReturnIsCorrect) { OsAgnosticMemoryManager mm(*executionEnvironment); auto gmmHelper = getGmmHelper(); auto ptr = mm.allocateSystemMemory(100, 0); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(ptr))); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, ptr, canonizedAddress, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); Gmm *gmm = GmmHelperFunctions::getGmm(allocation.getUnderlyingBuffer(), allocation.getUnderlyingBufferSize(), getGmmHelper()); allocation.setDefaultGmm(gmm); auto status = wddm->createAllocation(&allocation); EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.getDefaultHandle() != 0); auto error = wddm->mapGpuVirtualAddress(&allocation); EXPECT_TRUE(error); EXPECT_TRUE(allocation.getGpuAddress() != 0); error = wddm->makeResident(&allocation.getHandles()[0], allocation.getNumGmms(), false, nullptr, allocation.getAlignedSize()); EXPECT_TRUE(error); uint64_t sizeToTrim; error = wddm->evict(&allocation.getHandles()[0], allocation.getNumGmms(), sizeToTrim, true); EXPECT_TRUE(error); error = wddm->destroyAllocation(&allocation, osContext.get()); EXPECT_TRUE(error); delete gmm; mm.freeSystemMemory(allocation.getUnderlyingBuffer()); } TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandlesWhenCreateGraphicsAllocationFromSharedHandleIsCalledThenGraphicsAllocationsWithSharedPropertiesAreCreated) { void *pSysMem = (void *)0x1000; GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements)); std::unique_ptr gmm2(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_IMAGE, {}, gmmRequirements)); void *gmmPtrArray[]{gmm->gmmResourceInfo.get(), gmm2->gmmResourceInfo.get()}; auto status = setSizesFcn(gmmPtrArray, 2u, 1024u, 1u); EXPECT_EQ(0u, static_cast(status)); MemoryManagerCreate mm(false, false, *executionEnvironment); AllocationProperties properties(0, false, 4096u, AllocationType::sharedImage, false, {}); for (uint32_t i = 0; i < 3; i++) { WddmMemoryManager::OsHandleData osHandleData{ALLOCATION_HANDLE, i}; auto graphicsAllocation = mm.createGraphicsAllocationFromSharedHandle(osHandleData, properties, false, false, true, nullptr); auto wddmAllocation = (WddmAllocation *)graphicsAllocation; ASSERT_NE(nullptr, wddmAllocation); EXPECT_EQ(ALLOCATION_HANDLE, wddmAllocation->peekSharedHandle()); EXPECT_EQ(RESOURCE_HANDLE, wddmAllocation->getResourceHandle()); EXPECT_NE(0u, wddmAllocation->getDefaultHandle()); EXPECT_EQ(ALLOCATION_HANDLE, wddmAllocation->getDefaultHandle()); EXPECT_NE(0u, wddmAllocation->getGpuAddress()); EXPECT_EQ(4096u, wddmAllocation->getUnderlyingBufferSize()); EXPECT_EQ(nullptr, wddmAllocation->getAlignedCpuPtr()); EXPECT_NE(nullptr, wddmAllocation->getDefaultGmm()); EXPECT_EQ(4096u, wddmAllocation->getDefaultGmm()->gmmResourceInfo->getSizeAllocation()); if (i % 2) EXPECT_EQ(GMM_RESOURCE_USAGE_OCL_IMAGE, reinterpret_cast(wddmAllocation->getDefaultGmm()->gmmResourceInfo.get())->getResourceUsage()); else EXPECT_EQ(GMM_RESOURCE_USAGE_OCL_BUFFER, reinterpret_cast(wddmAllocation->getDefaultGmm()->gmmResourceInfo.get())->getResourceUsage()); mm.freeGraphicsMemory(graphicsAllocation); auto destroyWithResourceHandleCalled = 0u; D3DKMT_DESTROYALLOCATION2 *ptrToDestroyAlloc2 = nullptr; status = getSizesFcn(destroyWithResourceHandleCalled, ptrToDestroyAlloc2); EXPECT_EQ(0u, ptrToDestroyAlloc2->Flags.SynchronousDestroy); EXPECT_EQ(1u, ptrToDestroyAlloc2->Flags.AssumeNotInUse); EXPECT_EQ(0u, static_cast(status)); EXPECT_EQ(1u, destroyWithResourceHandleCalled); } } TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationFromSharedHandleIsCalledWithMapPointerThenGraphicsAllocationWithSharedPropertiesIsCreated) { void *pSysMem = (void *)0x1000; size_t sizeAlignedTo64Kb = 64 * MemoryConstants::kiloByte; void *reservedAddress; EXPECT_TRUE(wddm->reserveValidAddressRange(sizeAlignedTo64Kb, reservedAddress)); GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, sizeAlignedTo64Kb, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements)); void *gmmPtrArray[]{gmm->gmmResourceInfo.get()}; auto status = setSizesFcn(gmmPtrArray, 1u, 1024u, 1u); EXPECT_EQ(0u, static_cast(status)); MemoryManagerCreate mm(false, false, *executionEnvironment); AllocationProperties properties(0, false, sizeAlignedTo64Kb, AllocationType::sharedBuffer, false, {}); WddmMemoryManager::OsHandleData osHandleData{ALLOCATION_HANDLE}; auto graphicsAllocation = mm.createGraphicsAllocationFromSharedHandle(osHandleData, properties, false, false, true, reservedAddress); auto wddmAllocation = (WddmAllocation *)graphicsAllocation; ASSERT_NE(nullptr, wddmAllocation); EXPECT_EQ(ALLOCATION_HANDLE, wddmAllocation->peekSharedHandle()); EXPECT_EQ(RESOURCE_HANDLE, wddmAllocation->getResourceHandle()); EXPECT_NE(0u, wddmAllocation->getDefaultHandle()); EXPECT_EQ(ALLOCATION_HANDLE, wddmAllocation->getDefaultHandle()); EXPECT_EQ(reservedAddress, reinterpret_cast(wddmAllocation->getGpuAddress())); EXPECT_EQ(sizeAlignedTo64Kb, wddmAllocation->getUnderlyingBufferSize()); EXPECT_EQ(nullptr, wddmAllocation->getAlignedCpuPtr()); EXPECT_NE(nullptr, wddmAllocation->getDefaultGmm()); EXPECT_EQ(sizeAlignedTo64Kb, wddmAllocation->getDefaultGmm()->gmmResourceInfo->getSizeAllocation()); mm.freeGraphicsMemory(graphicsAllocation); wddm->releaseReservedAddress(nullptr); auto destroyWithResourceHandleCalled = 0u; D3DKMT_DESTROYALLOCATION2 *ptrToDestroyAlloc2 = nullptr; status = getSizesFcn(destroyWithResourceHandleCalled, ptrToDestroyAlloc2); EXPECT_EQ(0u, ptrToDestroyAlloc2->Flags.SynchronousDestroy); EXPECT_EQ(1u, ptrToDestroyAlloc2->Flags.AssumeNotInUse); EXPECT_EQ(0u, static_cast(status)); EXPECT_EQ(1u, destroyWithResourceHandleCalled); } TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationFromMultipleSharedHandlesIsCalledThenNullptrIsReturned) { void *pSysMem = (void *)0x1000; GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements)); void *gmmPtrArray[]{gmm->gmmResourceInfo.get()}; auto status = setSizesFcn(gmmPtrArray, 1u, 1024u, 1u); EXPECT_EQ(0u, static_cast(status)); MemoryManagerCreate mm(false, false, *executionEnvironment); AllocationProperties properties(0, false, 4096u, AllocationType::sharedBuffer, false, {}); std::vector handles{ALLOCATION_HANDLE}; auto graphicsAllocation = mm.createGraphicsAllocationFromMultipleSharedHandles(handles, properties, false, false, true, nullptr); ASSERT_EQ(nullptr, graphicsAllocation); } TEST_F(Wddm20WithMockGdiDllTests, givenSharedHandleWhenCreateGraphicsAllocationFromSharedHandleIsCalledThenMapGpuVaWithCpuPtrDepensOnBitness) { void *pSysMem = (void *)0x1000; GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; std::unique_ptr gmm(new Gmm(getGmmHelper(), pSysMem, 4096u, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements)); void *gmmPtrArray[]{gmm->gmmResourceInfo.get()}; auto status = setSizesFcn(gmmPtrArray, 1u, 1024u, 1u); EXPECT_EQ(0u, static_cast(status)); MemoryManagerCreate mm(false, false, *executionEnvironment); AllocationProperties properties(0, false, 4096, AllocationType::sharedBuffer, false, {}); WddmMemoryManager::OsHandleData osHandleData{ALLOCATION_HANDLE}; auto graphicsAllocation = mm.createGraphicsAllocationFromSharedHandle(osHandleData, properties, false, false, true, nullptr); auto wddmAllocation = (WddmAllocation *)graphicsAllocation; ASSERT_NE(nullptr, wddmAllocation); if (is32bit) { EXPECT_NE(wddm->mapGpuVirtualAddressResult.cpuPtrPassed, nullptr); } else { EXPECT_EQ(wddm->mapGpuVirtualAddressResult.cpuPtrPassed, nullptr); } mm.freeGraphicsMemory(graphicsAllocation); } TEST_F(Wddm20Tests, givenWddmCreatedWhenInitedThenMinAddressValid) { uintptr_t expected = windowsMinAddress; uintptr_t actual = wddm->getWddmMinAddress(); EXPECT_EQ(expected, actual); } TEST_F(Wddm20InstrumentationTest, GivenNoAdapterWhenConfiguringDeviceAddressSpaceThenFalseIsReturned) { auto gdi = std::make_unique(); wddm->resetGdi(gdi.release()); auto ret = wddm->configureDeviceAddressSpace(); EXPECT_FALSE(ret); EXPECT_EQ(0u, gmmMem->configureDeviceAddressSpaceCalled); } TEST_F(Wddm20InstrumentationTest, GivenNoDeviceWhenConfiguringDeviceAddressSpaceThenFalseIsReturned) { wddm->device = static_cast(0); auto ret = wddm->configureDeviceAddressSpace(); EXPECT_FALSE(ret); EXPECT_EQ(0u, gmmMem->configureDeviceAddressSpaceCalled); } TEST_F(Wddm20InstrumentationTest, GivenNoEscFuncWhenConfiguringDeviceAddressSpaceThenFalseIsReturned) { wddm->getGdi()->escape = static_cast(nullptr); auto ret = wddm->configureDeviceAddressSpace(); EXPECT_FALSE(ret); EXPECT_EQ(0u, gmmMem->configureDeviceAddressSpaceCalled); } TEST_F(Wddm20Tests, WhenGettingMaxApplicationAddressThen32Or64BitIsCorrectlyReturned) { uint64_t maxAddr = wddm->getMaxApplicationAddress(); if (is32bit) { EXPECT_EQ(maxAddr, MemoryConstants::max32BitAppAddress); } else { EXPECT_EQ(maxAddr, MemoryConstants::max64BitAppAddress); } } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, givenUseNoRingFlushesKmdModeDebugFlagToFalseWhenCreateContextIsCalledThenNoRingFlushesKmdModeIsSetToFalse) { DebugManagerStateRestore dbgRestore; debugManager.flags.UseNoRingFlushesKmdMode.set(false); init(); auto createContextParams = this->getCreateContextDataFcn(); auto privateData = (CREATECONTEXT_PVTDATA *)createContextParams->pPrivateDriverData; EXPECT_FALSE(!!privateData->NoRingFlushes); } struct WddmContextSchedulingPriorityTests : public Wddm20WithMockGdiDllTestsWithoutWddmInit { void initContext(bool lowPriority) { auto preemptionMode = PreemptionHelper::getDefaultPreemptionMode(*defaultHwInfo); wddmMockInterface = static_cast(wddm->wddmInterface.release()); wddm->init(); wddm->wddmInterface.reset(wddmMockInterface); auto &gfxCoreHelper = rootDeviceEnvironment->getHelper(); auto engine = gfxCoreHelper.getGpgpuEngineInstances(*rootDeviceEnvironment)[0]; auto engineDescriptor = EngineDescriptorHelper::getDefaultDescriptor(engine, preemptionMode); engineDescriptor.engineTypeUsage.second = lowPriority ? EngineUsage::lowPriority : EngineUsage::regular; osContext = std::make_unique(*osInterface->getDriverModel()->as(), 0, 0u, engineDescriptor); osContext->ensureContextInitialized(false); } }; TEST_F(WddmContextSchedulingPriorityTests, givenLowPriorityContextWhenInitializingThenCallSetPriority) { initContext(true); auto createContextParams = this->getSetContextSchedulingPriorityDataCallFcn(); EXPECT_EQ(osContext->getWddmContextHandle(), createContextParams->hContext); EXPECT_EQ(-7, createContextParams->Priority); } TEST_F(WddmContextSchedulingPriorityTests, givenLowPriorityContextWhenFailingDuringSetSchedulingPriorityThenThrow) { *this->getFailOnSetContextSchedulingPriorityCallFcn() = true; EXPECT_ANY_THROW(initContext(true)); } TEST_F(WddmContextSchedulingPriorityTests, givenDebugFlagSetWhenInitializingLowPriorityContextThenSetPriorityValue) { DebugManagerStateRestore dbgRestore; constexpr int32_t newPriority = 3; debugManager.flags.ForceWddmLowPriorityContextValue.set(newPriority); initContext(true); auto createContextParams = this->getSetContextSchedulingPriorityDataCallFcn(); EXPECT_EQ(osContext->getWddmContextHandle(), createContextParams->hContext); EXPECT_EQ(newPriority, createContextParams->Priority); } TEST_F(WddmContextSchedulingPriorityTests, givenRegularContextWhenInitializingThenDontCallSetPriority) { initContext(false); auto createContextParams = this->getSetContextSchedulingPriorityDataCallFcn(); EXPECT_EQ(0u, createContextParams->hContext); EXPECT_EQ(0, createContextParams->Priority); } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, givenCreateContextCallWhenDriverHintsThenItPointsToOpenCL) { init(); auto createContextParams = this->getCreateContextDataFcn(); EXPECT_EQ(D3DKMT_CLIENTHINT_OPENCL, createContextParams->ClientHint); } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, givenUseNoRingFlushesKmdModeDebugFlagToTrueWhenCreateContextIsCalledThenNoRingFlushesKmdModeIsSetToTrue) { DebugManagerStateRestore dbgRestore; debugManager.flags.UseNoRingFlushesKmdMode.set(true); init(); auto createContextParams = this->getCreateContextDataFcn(); auto privateData = (CREATECONTEXT_PVTDATA *)createContextParams->pPrivateDriverData; EXPECT_TRUE(!!privateData->NoRingFlushes); } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, whenCreateContextIsCalledThenDummyPageBackingEnabledFlagIsDisabled) { init(); auto createContextParams = this->getCreateContextDataFcn(); auto privateData = (CREATECONTEXT_PVTDATA *)createContextParams->pPrivateDriverData; EXPECT_FALSE(!!privateData->DummyPageBackingEnabled); } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, givenDummyPageBackingEnabledFlagSetToTrueWhenCreateContextIsCalledThenFlagIsEnabled) { DebugManagerStateRestore dbgRestore; debugManager.flags.DummyPageBackingEnabled.set(true); init(); auto createContextParams = this->getCreateContextDataFcn(); auto privateData = (CREATECONTEXT_PVTDATA *)createContextParams->pPrivateDriverData; EXPECT_TRUE(!!privateData->DummyPageBackingEnabled); } TEST_F(Wddm20WithMockGdiDllTestsWithoutWddmInit, givenEngineTypeWhenCreatingContextThenPassCorrectNodeOrdinal) { init(); auto createContextParams = this->getCreateContextDataFcn(); auto &gfxCoreHelper = this->rootDeviceEnvironment->getHelper(); UINT expected = WddmEngineMapper::engineNodeMap(gfxCoreHelper.getGpgpuEngineInstances(*rootDeviceEnvironment)[0].first); EXPECT_EQ(expected, createContextParams->NodeOrdinal); } TEST_F(Wddm20WithMockGdiDllTests, whenCreateContextIsCalledThenDisableHwQueues) { EXPECT_FALSE(wddm->wddmInterface->hwQueuesSupported()); EXPECT_EQ(0u, getCreateContextDataFcn()->Flags.HwQueueSupported); } TEST_F(Wddm20WithMockGdiDllTests, givenDestructionOsContextWinWhenCallingDestroyMonitorFenceThenDoCallGdiDestroy) { auto fenceHandle = osContext->getResidencyController().getMonitoredFence().fenceHandle; osContext.reset(nullptr); EXPECT_EQ(1u, wddmMockInterface->destroyMonitorFenceCalled); EXPECT_EQ(fenceHandle, getDestroySynchronizationObjectDataFcn()->hSyncObject); } TEST_F(Wddm20Tests, whenCreateHwQueueIsCalledThenAlwaysReturnFalse) { EXPECT_FALSE(wddm->wddmInterface->createHwQueue(*osContext.get())); } TEST_F(Wddm20Tests, whenWddmIsInitializedThenGdiDoesntHaveHwQueueDDIs) { EXPECT_EQ(nullptr, wddm->getGdi()->createHwQueue.mFunc); EXPECT_EQ(nullptr, wddm->getGdi()->destroyHwQueue.mFunc); EXPECT_EQ(nullptr, wddm->getGdi()->submitCommandToHwQueue.mFunc); } TEST(DebugFlagTest, givenDebugManagerWhenGetForUseNoRingFlushesKmdModeIsCalledThenTrueIsReturned) { EXPECT_TRUE(debugManager.flags.UseNoRingFlushesKmdMode.get()); } TEST_F(Wddm20Tests, GivenMultipleHandlesWhenMakingResidentThenAllocationListIsCorrect) { D3DKMT_HANDLE handles[2] = {ALLOCATION_HANDLE, ALLOCATION_HANDLE}; gdi->getMakeResidentArg().NumAllocations = 0; gdi->getMakeResidentArg().AllocationList = nullptr; wddm->callBaseMakeResident = true; bool error = wddm->makeResident(handles, 2, false, nullptr, 0x1000); EXPECT_TRUE(error); EXPECT_EQ(2u, gdi->getMakeResidentArg().NumAllocations); EXPECT_EQ(handles, gdi->getMakeResidentArg().AllocationList); } TEST_F(Wddm20Tests, GivenMultipleHandlesWhenMakingResidentThenBytesToTrimIsCorrect) { D3DKMT_HANDLE handles[2] = {ALLOCATION_HANDLE, ALLOCATION_HANDLE}; gdi->getMakeResidentArg().NumAllocations = 0; gdi->getMakeResidentArg().AllocationList = nullptr; gdi->getMakeResidentArg().NumBytesToTrim = 30; wddm->callBaseMakeResident = true; uint64_t bytesToTrim = 0; bool success = wddm->makeResident(handles, 2, false, &bytesToTrim, 0x1000); EXPECT_TRUE(success); EXPECT_EQ(gdi->getMakeResidentArg().NumBytesToTrim, bytesToTrim); } TEST_F(Wddm20Tests, WhenMakingNonResidentAndEvictNotNeededThenEvictIsCalledWithProperFlagSet) { DebugManagerStateRestore restorer{}; debugManager.flags.PlaformSupportEvictIfNecessaryFlag.set(1); auto &productHelper = rootDeviceEnvironment->getHelper(); wddm->setPlatformSupportEvictIfNecessaryFlag(productHelper); D3DKMT_HANDLE handle = (D3DKMT_HANDLE)0x1234; gdi->getEvictArg().AllocationList = nullptr; gdi->getEvictArg().Flags.Value = 0; gdi->getEvictArg().hDevice = 0; gdi->getEvictArg().NumAllocations = 0; gdi->getEvictArg().NumBytesToTrim = 20; wddm->callBaseEvict = true; uint64_t sizeToTrim = 10; wddm->evict(&handle, 1, sizeToTrim, false); EXPECT_EQ(1u, gdi->getEvictArg().NumAllocations); EXPECT_EQ(&handle, gdi->getEvictArg().AllocationList); EXPECT_EQ(wddm->getDeviceHandle(), gdi->getEvictArg().hDevice); EXPECT_EQ(0u, gdi->getEvictArg().NumBytesToTrim); EXPECT_EQ(1u, gdi->getEvictArg().Flags.EvictOnlyIfNecessary); } TEST_F(Wddm20Tests, WhenMakingNonResidentAndEvictNeededThenEvictIsCalledWithProperFlagSet) { D3DKMT_HANDLE handle = (D3DKMT_HANDLE)0x1234; gdi->getEvictArg().AllocationList = nullptr; gdi->getEvictArg().Flags.Value = 0; gdi->getEvictArg().hDevice = 0; gdi->getEvictArg().NumAllocations = 0; gdi->getEvictArg().NumBytesToTrim = 20; wddm->callBaseEvict = true; uint64_t sizeToTrim = 10; wddm->evict(&handle, 1, sizeToTrim, true); EXPECT_EQ(1u, gdi->getEvictArg().NumAllocations); EXPECT_EQ(&handle, gdi->getEvictArg().AllocationList); EXPECT_EQ(wddm->getDeviceHandle(), gdi->getEvictArg().hDevice); EXPECT_EQ(0u, gdi->getEvictArg().NumBytesToTrim); EXPECT_EQ(0u, gdi->getEvictArg().Flags.EvictOnlyIfNecessary); } TEST_F(Wddm20Tests, givenDestroyAllocationWhenItIsCalledThenAllocationIsPassedToDestroyAllocation) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.getResidencyData().updateCompletionData(10, osContext->getContextId()); allocation.handle = ALLOCATION_HANDLE; *osContext->getResidencyController().getMonitoredFence().cpuAddress = 10; gdi->getWaitFromCpuArg().FenceValueArray = nullptr; gdi->getWaitFromCpuArg().Flags.Value = 0; gdi->getWaitFromCpuArg().hDevice = (D3DKMT_HANDLE)0; gdi->getWaitFromCpuArg().ObjectCount = 0; gdi->getWaitFromCpuArg().ObjectHandleArray = nullptr; gdi->getDestroyArg().AllocationCount = 0; gdi->getDestroyArg().Flags.Value = 0; gdi->getDestroyArg().hDevice = (D3DKMT_HANDLE)0; gdi->getDestroyArg().hResource = (D3DKMT_HANDLE)0; gdi->getDestroyArg().phAllocationList = nullptr; wddm->destroyAllocation(&allocation, osContext.get()); EXPECT_EQ(wddm->getDeviceHandle(), gdi->getDestroyArg().hDevice); EXPECT_EQ(static_cast(allocation.getHandles().size()), gdi->getDestroyArg().AllocationCount); EXPECT_NE(nullptr, gdi->getDestroyArg().phAllocationList); } TEST_F(Wddm20Tests, WhenLastFenceLessEqualThanMonitoredThenWaitFromCpuIsNotCalled) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.getResidencyData().updateCompletionData(10, osContext->getContextId()); allocation.handle = ALLOCATION_HANDLE; *osContext->getResidencyController().getMonitoredFence().cpuAddress = 10; gdi->getWaitFromCpuArg().FenceValueArray = nullptr; gdi->getWaitFromCpuArg().Flags.Value = 0; gdi->getWaitFromCpuArg().hDevice = (D3DKMT_HANDLE)0; gdi->getWaitFromCpuArg().ObjectCount = 0; gdi->getWaitFromCpuArg().ObjectHandleArray = nullptr; auto status = wddm->waitFromCpu(10, osContext->getResidencyController().getMonitoredFence(), true); EXPECT_TRUE(status); EXPECT_EQ(nullptr, gdi->getWaitFromCpuArg().FenceValueArray); EXPECT_EQ((D3DKMT_HANDLE)0, gdi->getWaitFromCpuArg().hDevice); EXPECT_EQ(0u, gdi->getWaitFromCpuArg().ObjectCount); EXPECT_EQ(nullptr, gdi->getWaitFromCpuArg().ObjectHandleArray); } TEST_F(Wddm20Tests, WhenLastFenceGreaterThanMonitoredThenWaitFromCpuIsCalled) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.getResidencyData().updateCompletionData(10, osContext->getContextId()); allocation.handle = ALLOCATION_HANDLE; *osContext->getResidencyController().getMonitoredFence().cpuAddress = 10; gdi->getWaitFromCpuArg().FenceValueArray = nullptr; gdi->getWaitFromCpuArg().Flags.Value = 0; gdi->getWaitFromCpuArg().hDevice = (D3DKMT_HANDLE)0; gdi->getWaitFromCpuArg().ObjectCount = 0; gdi->getWaitFromCpuArg().ObjectHandleArray = nullptr; auto status = wddm->waitFromCpu(20, osContext->getResidencyController().getMonitoredFence(), true); EXPECT_TRUE(status); EXPECT_NE(nullptr, gdi->getWaitFromCpuArg().FenceValueArray); EXPECT_EQ((D3DKMT_HANDLE)wddm->getDeviceHandle(), gdi->getWaitFromCpuArg().hDevice); EXPECT_EQ(1u, gdi->getWaitFromCpuArg().ObjectCount); EXPECT_NE(nullptr, gdi->getWaitFromCpuArg().ObjectHandleArray); } TEST_F(Wddm20Tests, WhenCreatingMonitoredFenceThenItIsInitializedWithFenceValueZeroAndCurrentFenceValueIsSetToOne) { gdi->createSynchronizationObject2 = gdi->createSynchronizationObject2Mock; gdi->getCreateSynchronizationObject2Arg().Info.MonitoredFence.InitialFenceValue = 300; wddm->wddmInterface->createMonitoredFence(*osContext); EXPECT_EQ(0u, gdi->getCreateSynchronizationObject2Arg().Info.MonitoredFence.InitialFenceValue); EXPECT_EQ(1u, osContext->getResidencyController().getMonitoredFence().currentFenceValue); } NTSTATUS APIENTRY queryResourceInfoMock(D3DKMT_QUERYRESOURCEINFO *pData) { pData->NumAllocations = 0; return 0; } TEST_F(Wddm20Tests, givenOpenSharedHandleWhenZeroAllocationsThenReturnNull) { MockMemoryManager::OsHandleData osHandleData{static_cast(0ull)}; WddmAllocation *alloc = nullptr; gdi->queryResourceInfo = reinterpret_cast(queryResourceInfoMock); auto ret = wddm->openSharedHandle(osHandleData, alloc); EXPECT_EQ(false, ret); } TEST_F(Wddm20Tests, givenOpenNTHandleWhenZeroAllocationsThenReturnNull) { MockMemoryManager::OsHandleData osHandleData{static_cast(0ull)}; WddmAllocation *alloc = nullptr; auto ret = wddm->openNTHandle(osHandleData, alloc); EXPECT_EQ(false, ret); } TEST_F(Wddm20Tests, whenCreateAllocation64kFailsThenReturnFalse) { struct FailingCreateAllocation { static NTSTATUS APIENTRY mockCreateAllocation2(D3DKMT_CREATEALLOCATION *param) { return STATUS_GRAPHICS_NO_VIDEO_MEMORY; }; }; gdi->createAllocation2 = FailingCreateAllocation::mockCreateAllocation2; void *fakePtr = reinterpret_cast(0x123); auto gmmHelper = getGmmHelper(); auto canonizedAddress = gmmHelper->canonize(castToUint64(const_cast(fakePtr))); GmmRequirements gmmRequirements{}; gmmRequirements.allowLargePages = true; gmmRequirements.preferCompressed = false; auto gmm = std::make_unique(rootDeviceEnvironment->getGmmHelper(), fakePtr, 100, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, StorageInfo{}, gmmRequirements); WddmAllocation allocation(0, 1u /*num gmms*/, AllocationType::unknown, fakePtr, canonizedAddress, 100, nullptr, MemoryPool::memoryNull, 0u, 1u); allocation.setDefaultGmm(gmm.get()); EXPECT_FALSE(wddm->createAllocation64k(&allocation)); } TEST_F(Wddm20Tests, givenReadOnlyMemoryWhenCreateAllocationFailsWithNoVideoMemoryThenCorrectStatusIsReturned) { class MockCreateAllocation { public: static NTSTATUS APIENTRY mockCreateAllocation2(D3DKMT_CREATEALLOCATION *param) { return STATUS_GRAPHICS_NO_VIDEO_MEMORY; }; }; gdi->createAllocation2 = MockCreateAllocation::mockCreateAllocation2; OsHandleStorage handleStorage; OsHandleWin handle; auto maxOsContextCount = 1u; ResidencyData residency(maxOsContextCount); handleStorage.fragmentCount = 1; handleStorage.fragmentStorageData[0].cpuPtr = (void *)0x1000; handleStorage.fragmentStorageData[0].fragmentSize = 0x1000; handleStorage.fragmentStorageData[0].freeTheFragment = false; handleStorage.fragmentStorageData[0].osHandleStorage = &handle; handleStorage.fragmentStorageData[0].residency = &residency; handle.gmm = GmmHelperFunctions::getGmm(nullptr, 0, getGmmHelper()); NTSTATUS result = wddm->createAllocationsAndMapGpuVa(handleStorage); EXPECT_EQ(STATUS_GRAPHICS_NO_VIDEO_MEMORY, result); delete handle.gmm; } TEST_F(Wddm20Tests, whenContextIsInitializedThenApplyAdditionalContextFlagsIsCalled) { auto result = wddm->init(); EXPECT_TRUE(result); EXPECT_EQ(1u, wddm->applyAdditionalContextFlagsResult.called); } TEST_F(Wddm20Tests, givenTrimCallbackRegistrationIsDisabledInDebugVariableWhenRegisteringCallbackThenReturnNullptr) { DebugManagerStateRestore stateRestore; debugManager.flags.DoNotRegisterTrimCallback.set(true); WddmResidencyController residencyController{*wddm, 0u}; EXPECT_EQ(nullptr, wddm->registerTrimCallback([](D3DKMT_TRIMNOTIFICATION *) {}, residencyController)); } using WddmLockWithMakeResidentTests = Wddm20Tests; TEST_F(WddmLockWithMakeResidentTests, givenAllocationThatDoesntNeedMakeResidentBeforeLockWhenLockThenDontStoreItOrCallMakeResident) { EXPECT_TRUE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(0u, wddm->makeResidentResult.called); wddm->lockResource(ALLOCATION_HANDLE, false, 0x1000); EXPECT_TRUE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(0u, wddm->makeResidentResult.called); wddm->unlockResource(ALLOCATION_HANDLE, false); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationThatNeedsMakeResidentBeforeLockWhenLockThenCallBlockingMakeResident) { wddm->lockResource(ALLOCATION_HANDLE, true, 0x1000); EXPECT_EQ(1u, wddm->makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationAndForcePagingFenceTrueWhenApplyBlockingMakeResidentThenWaitOnPagingFenceFromCpuIsCalledWithIsKmdWaitNeededAsFalse) { auto allocHandle = ALLOCATION_HANDLE; const bool forcePagingFence = true; wddm->temporaryResources->makeResidentResources(&allocHandle, 1u, 0x1000, forcePagingFence); EXPECT_EQ(1u, mockTemporaryResources->acquireLockResult.called); EXPECT_EQ(reinterpret_cast(&mockTemporaryResources->resourcesLock), mockTemporaryResources->acquireLockResult.uint64ParamPassed); EXPECT_NE(forcePagingFence, wddm->waitOnPagingFenceFromCpuResult.isKmdWaitNeededPassed); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationWhenApplyBlockingMakeResidentThenAcquireUniqueLock) { wddm->temporaryResources->makeResidentResource(ALLOCATION_HANDLE, 0x1000); EXPECT_EQ(1u, mockTemporaryResources->acquireLockResult.called); EXPECT_EQ(reinterpret_cast(&mockTemporaryResources->resourcesLock), mockTemporaryResources->acquireLockResult.uint64ParamPassed); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationWhenApplyBlockingMakeResidentThenCallMakeResidentAndStoreAllocation) { wddm->temporaryResources->makeResidentResource(ALLOCATION_HANDLE, 0x1000); EXPECT_EQ(1u, wddm->makeResidentResult.called); EXPECT_EQ(ALLOCATION_HANDLE, mockTemporaryResources->resourceHandles.back()); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationWhenApplyBlockingMakeResidentThenWaitForCurrentPagingFenceValue) { wddm->callBaseMakeResident = true; wddm->mockPagingFence = 0u; wddm->temporaryResources->makeResidentResource(ALLOCATION_HANDLE, 0x1000); UINT64 expectedCallNumber = NEO::wddmResidencyLoggingAvailable ? MockGdi::pagingFenceReturnValue + 1 : 0ull; EXPECT_EQ(1u, wddm->makeResidentResult.called); EXPECT_EQ(MockGdi::pagingFenceReturnValue + 1, wddm->mockPagingFence); EXPECT_EQ(expectedCallNumber, wddm->getPagingFenceAddressResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenAllocationWhenApplyBlockingMakeResidentAndMakeResidentCallFailsThenEvictTemporaryResourcesAndRetry) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.handle = 0x3; WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); mockWddm.makeResidentStatus = false; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockWddm.temporaryResources->makeResidentResource(allocation.handle, 0x1000); EXPECT_EQ(1u, mockTemporaryResources->evictAllResourcesResult.called); EXPECT_EQ(allocation.handle, mockWddm.makeResidentResult.handlePack[0]); EXPECT_EQ(2u, mockWddm.makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenApplyBlockingMakeResidentAndTemporaryResourcesAreEvictedSuccessfullyThenCallMakeResidentOneMoreTime) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.handle = 0x3; WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); mockWddm.makeResidentStatus = false; mockWddm.callBaseEvict = true; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(allocation.handle); mockWddm.temporaryResources->makeResidentResource(allocation.handle, 0x1000); EXPECT_EQ(2u, mockTemporaryResources->evictAllResourcesResult.called); EXPECT_EQ(1u, mockWddm.evictResult.called); EXPECT_EQ(0u, gdi->getEvictArg().Flags.EvictOnlyIfNecessary); EXPECT_EQ(allocation.handle, mockWddm.makeResidentResult.handlePack[0]); EXPECT_EQ(3u, mockWddm.makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenApplyBlockingMakeResidentAndMakeResidentStillFailsThenDontStoreTemporaryResource) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.handle = 0x2; WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); mockWddm.makeResidentStatus = false; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(0x1); EXPECT_EQ(1u, mockTemporaryResources->resourceHandles.size()); mockWddm.temporaryResources->makeResidentResource(allocation.handle, 0x1000); EXPECT_EQ(0u, mockTemporaryResources->resourceHandles.size()); EXPECT_EQ(1u, mockWddm.evictResult.called); EXPECT_EQ(allocation.handle, mockWddm.makeResidentResult.handlePack[0]); EXPECT_TRUE(mockWddm.makeResidentResult.cantTrimFurther); EXPECT_EQ(3u, mockWddm.makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenApplyBlockingMakeResidentAndMakeResidentPassesAfterEvictThenStoreTemporaryResource) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.handle = 0x2; WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); mockWddm.makeResidentResults = {false, true}; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(0x1); EXPECT_EQ(1u, mockTemporaryResources->resourceHandles.size()); mockWddm.temporaryResources->makeResidentResource(allocation.handle, 0x1000); EXPECT_EQ(1u, mockTemporaryResources->resourceHandles.size()); EXPECT_EQ(0x2u, mockTemporaryResources->resourceHandles.back()); EXPECT_EQ(1u, mockWddm.evictResult.called); EXPECT_EQ(allocation.handle, mockWddm.makeResidentResult.handlePack[0]); EXPECT_EQ(2u, mockWddm.makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenApplyBlockingMakeResidentAndMakeResidentPassesThenStoreTemporaryResource) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.handle = 0x2; WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(0x1); mockWddm.temporaryResources->makeResidentResource(allocation.handle, 0x1000); EXPECT_EQ(2u, mockTemporaryResources->resourceHandles.size()); EXPECT_EQ(0x2u, mockTemporaryResources->resourceHandles.back()); EXPECT_EQ(allocation.handle, mockWddm.makeResidentResult.handlePack[0]); EXPECT_EQ(1u, mockWddm.makeResidentResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenNoTemporaryResourcesWhenEvictingAllTemporaryResourcesThenEvictionIsNotApplied) { wddm->getTemporaryResourcesContainer()->evictAllResources(); EXPECT_EQ(MemoryOperationsStatus::memoryNotFound, mockTemporaryResources->evictAllResourcesResult.operationSuccess); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingAllTemporaryResourcesThenAcquireTemporaryResourcesLock) { wddm->getTemporaryResourcesContainer()->evictAllResources(); EXPECT_EQ(1u, mockTemporaryResources->acquireLockResult.called); EXPECT_EQ(reinterpret_cast(&mockTemporaryResources->resourcesLock), mockTemporaryResources->acquireLockResult.uint64ParamPassed); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingAllTemporaryResourcesAndAllEvictionsSucceedThenReturnSuccess) { MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(allocation.handle); mockWddm.getTemporaryResourcesContainer()->evictAllResources(); EXPECT_EQ(1u, mockTemporaryResources->evictAllResourcesResult.called); EXPECT_EQ(MemoryOperationsStatus::success, mockTemporaryResources->evictAllResourcesResult.operationSuccess); EXPECT_EQ(1u, mockWddm.evictResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenThreeAllocationsWhenEvictingAllTemporaryResourcesThenCallEvictForEachAllocationAndCleanList) { WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); constexpr uint32_t numAllocations = 3u; for (auto i = 0u; i < numAllocations; i++) { mockTemporaryResources->resourceHandles.push_back(i); } mockWddm.getTemporaryResourcesContainer()->evictAllResources(); EXPECT_TRUE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(1u, mockWddm.evictResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenThreeAllocationsWhenEvictingAllTemporaryResourcesAndOneOfThemFailsThenReturnFail) { WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0].get()); mockWddm.evictStatus = false; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); constexpr uint32_t numAllocations = 3u; for (auto i = 0u; i < numAllocations; i++) { mockTemporaryResources->resourceHandles.push_back(i); } mockWddm.getTemporaryResourcesContainer()->evictAllResources(); EXPECT_EQ(MemoryOperationsStatus::failed, mockTemporaryResources->evictAllResourcesResult.operationSuccess); EXPECT_EQ(1u, mockWddm.evictResult.called); } TEST_F(WddmLockWithMakeResidentTests, givenNoTemporaryResourcesWhenEvictingTemporaryResourceThenEvictionIsNotApplied) { wddm->getTemporaryResourcesContainer()->evictResource(ALLOCATION_HANDLE); EXPECT_EQ(MemoryOperationsStatus::memoryNotFound, mockTemporaryResources->evictResourceResult.operationSuccess); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingTemporaryResourceThenAcquireTemporaryResourcesLock) { wddm->getTemporaryResourcesContainer()->evictResource(ALLOCATION_HANDLE); EXPECT_EQ(1u, mockTemporaryResources->acquireLockResult.called); EXPECT_EQ(reinterpret_cast(&mockTemporaryResources->resourcesLock), mockTemporaryResources->acquireLockResult.uint64ParamPassed); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingNonExistingTemporaryResourceThenEvictIsNotAppliedAndTemporaryResourcesAreRestored) { mockTemporaryResources->resourceHandles.push_back(ALLOCATION_HANDLE); EXPECT_FALSE(mockTemporaryResources->resourceHandles.empty()); wddm->getTemporaryResourcesContainer()->evictResource(ALLOCATION_HANDLE + 1); EXPECT_FALSE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(MemoryOperationsStatus::memoryNotFound, mockTemporaryResources->evictResourceResult.operationSuccess); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingTemporaryResourceAndEvictFailsThenReturnFail) { WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); mockWddm.evictStatus = false; auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(ALLOCATION_HANDLE); mockWddm.getTemporaryResourcesContainer()->evictResource(ALLOCATION_HANDLE); EXPECT_TRUE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(MemoryOperationsStatus::failed, mockTemporaryResources->evictResourceResult.operationSuccess); EXPECT_EQ(1u, mockWddm.evictResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingTemporaryResourceAndEvictSucceedThenReturnSuccess) { WddmMock mockWddm(*executionEnvironment->rootDeviceEnvironments[0]); auto mockTemporaryResources = static_cast(mockWddm.temporaryResources.get()); mockTemporaryResources->resourceHandles.push_back(ALLOCATION_HANDLE); mockWddm.getTemporaryResourcesContainer()->evictResource(ALLOCATION_HANDLE); EXPECT_TRUE(mockTemporaryResources->resourceHandles.empty()); EXPECT_EQ(MemoryOperationsStatus::success, mockTemporaryResources->evictResourceResult.operationSuccess); EXPECT_EQ(1u, mockWddm.evictResult.called); } TEST_F(WddmLockWithMakeResidentTests, whenEvictingTemporaryResourceThenOtherResourcesRemainOnTheList) { mockTemporaryResources->resourceHandles.push_back(0x1); mockTemporaryResources->resourceHandles.push_back(0x2); mockTemporaryResources->resourceHandles.push_back(0x3); wddm->getTemporaryResourcesContainer()->evictResource(0x2); EXPECT_EQ(2u, mockTemporaryResources->resourceHandles.size()); EXPECT_EQ(0x1u, mockTemporaryResources->resourceHandles.front()); EXPECT_EQ(0x3u, mockTemporaryResources->resourceHandles.back()); } TEST_F(WddmLockWithMakeResidentTests, whenAlllocationNeedsBlockingMakeResidentBeforeLockThenLockWithBlockingMakeResident) { WddmMemoryManager memoryManager(*executionEnvironment); MockWddmAllocation allocation(rootDeviceEnvironment->getGmmHelper()); allocation.setMakeResidentBeforeLockRequired(false); memoryManager.lockResource(&allocation); EXPECT_EQ(1u, wddm->lockResult.called); EXPECT_EQ(rootDeviceEnvironment->getHelper().makeResidentBeforeLockNeeded(false), wddm->lockResult.uint64ParamPassed); memoryManager.unlockResource(&allocation); allocation.setMakeResidentBeforeLockRequired(true); memoryManager.lockResource(&allocation); EXPECT_EQ(2u, wddm->lockResult.called); EXPECT_EQ(1u, wddm->lockResult.uint64ParamPassed); memoryManager.unlockResource(&allocation); } using WddmGfxPartitionTest = Wddm20Tests; TEST(WddmGfxPartitionTests, givenGfxPartitionWhenInitializedThenInternalFrontWindowHeapIsAllocatedAtInternalHeapFront) { MockExecutionEnvironment executionEnvironment; auto wddm = new WddmMock(*executionEnvironment.rootDeviceEnvironments[0]); uint32_t rootDeviceIndex = 0; size_t numRootDevices = 1; MockGfxPartition gfxPartition; wddm->init(); wddm->initGfxPartition(gfxPartition, rootDeviceIndex, numRootDevices, false); EXPECT_EQ(gfxPartition.getHeapBase(HeapIndex::heapInternalFrontWindow), gfxPartition.getHeapBase(HeapIndex::heapInternal)); EXPECT_EQ(gfxPartition.getHeapBase(HeapIndex::heapInternalDeviceFrontWindow), gfxPartition.getHeapBase(HeapIndex::heapInternalDeviceMemory)); auto frontWindowSize = GfxPartition::internalFrontWindowPoolSize; EXPECT_EQ(gfxPartition.getHeapSize(HeapIndex::heapInternalFrontWindow), frontWindowSize); EXPECT_EQ(gfxPartition.getHeapSize(HeapIndex::heapInternalDeviceFrontWindow), frontWindowSize); EXPECT_EQ(gfxPartition.getHeapMinimalAddress(HeapIndex::heapInternalFrontWindow), gfxPartition.getHeapBase(HeapIndex::heapInternalFrontWindow)); EXPECT_EQ(gfxPartition.getHeapMinimalAddress(HeapIndex::heapInternalDeviceFrontWindow), gfxPartition.getHeapBase(HeapIndex::heapInternalDeviceFrontWindow)); EXPECT_EQ(gfxPartition.getHeapMinimalAddress(HeapIndex::heapInternal), gfxPartition.getHeapBase(HeapIndex::heapInternal) + frontWindowSize); EXPECT_EQ(gfxPartition.getHeapMinimalAddress(HeapIndex::heapInternalDeviceMemory), gfxPartition.getHeapBase(HeapIndex::heapInternalDeviceMemory) + frontWindowSize); EXPECT_EQ(gfxPartition.getHeapLimit(HeapIndex::heapInternal), gfxPartition.getHeapBase(HeapIndex::heapInternal) + gfxPartition.getHeapSize(HeapIndex::heapInternal) - 1); EXPECT_EQ(gfxPartition.getHeapLimit(HeapIndex::heapInternalDeviceMemory), gfxPartition.getHeapBase(HeapIndex::heapInternalDeviceMemory) + gfxPartition.getHeapSize(HeapIndex::heapInternalDeviceMemory) - 1); } TEST(WddmGfxPartitionTests, givenInternalFrontWindowHeapWhenAllocatingSmallOrBigChunkThenAddressFromFrontIsReturned) { MockExecutionEnvironment executionEnvironment; auto wddm = new WddmMock(*executionEnvironment.rootDeviceEnvironments[0]); uint32_t rootDeviceIndex = 0; size_t numRootDevices = 1; MockGfxPartition gfxPartition; wddm->init(); wddm->initGfxPartition(gfxPartition, rootDeviceIndex, numRootDevices, false); const size_t sizeSmall = MemoryConstants::pageSize64k; const size_t sizeBig = static_cast(gfxPartition.getHeapSize(HeapIndex::heapInternalFrontWindow)) - MemoryConstants::pageSize64k; HeapIndex heaps[] = {HeapIndex::heapInternalFrontWindow, HeapIndex::heapInternalDeviceFrontWindow}; for (int i = 0; i < 2; i++) { size_t sizeToAlloc = sizeSmall; auto address = gfxPartition.heapAllocate(heaps[i], sizeToAlloc); EXPECT_EQ(gfxPartition.getHeapBase(heaps[i]), address); gfxPartition.heapFree(heaps[i], address, sizeToAlloc); sizeToAlloc = sizeBig; address = gfxPartition.heapAllocate(heaps[i], sizeToAlloc); EXPECT_EQ(gfxPartition.getHeapBase(heaps[i]), address); gfxPartition.heapFree(heaps[i], address, sizeToAlloc); } } TEST_F(Wddm20Tests, givenWddmWhenDiscoverDevicesAndFilterDeviceIdIsTheSameAsTheExistingDeviceThenReturnTheAdapter) { DebugManagerStateRestore stateRestore; debugManager.flags.FilterDeviceId.set("1234"); // Existing device Id ExecutionEnvironment executionEnvironment; auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment); EXPECT_EQ(1u, hwDeviceIds.size()); EXPECT_NE(nullptr, hwDeviceIds[0].get()); } TEST_F(WddmTest, WhenFeatureFlagHwQueueIsDisabledThenReturnWddm20Version) { wddm->featureTable->flags.ftrWddmHwQueues = 0; EXPECT_EQ(WddmVersion::wddm20, wddm->getWddmVersion()); } TEST_F(WddmTest, WhenFeatureFlagHwQueueIsEnabledThenReturnWddm23Version) { wddm->featureTable->flags.ftrWddmHwQueues = 1; EXPECT_EQ(WddmVersion::wddm23, wddm->getWddmVersion()); } TEST_F(Wddm20WithMockGdiDllTests, GivenCreationSucceedWhenCreatingSeparateMonitorFenceThenReturnFilledStructure) { MonitoredFence monitorFence = {0}; bool ret = wddmMockInterface->createMonitoredFence(monitorFence); EXPECT_TRUE(ret); EXPECT_EQ(4u, monitorFence.fenceHandle); EXPECT_EQ(getMonitorFenceCpuFenceAddressFcn(), monitorFence.cpuAddress); } TEST_F(Wddm20WithMockGdiDllTests, GivenCreationFailWhenCreatingSeparateMonitorFenceThenReturnNotFilledStructure) { MonitoredFence monitorFence = {0}; *getCreateSynchronizationObject2FailCallFcn() = true; bool ret = wddmMockInterface->createMonitoredFence(monitorFence); EXPECT_FALSE(ret); EXPECT_EQ(0u, monitorFence.fenceHandle); void *retAddress = reinterpret_cast(0); EXPECT_EQ(retAddress, monitorFence.cpuAddress); } TEST_F(Wddm20WithMockGdiDllTests, WhenDestroyingSeparateMonitorFenceThenExpectGdiCalled) { MonitoredFence monitorFence = {0}; monitorFence.fenceHandle = 10u; wddmMockInterface->destroyMonitorFence(monitorFence); EXPECT_EQ(monitorFence.fenceHandle, getDestroySynchronizationObjectDataFcn()->hSyncObject); } TEST_F(Wddm20WithMockGdiDllTests, whenSetDeviceInfoFailsThenDeviceIsNotConfigured) { auto mockGmmMemory = new MockGmmMemoryBase(getGmmClientContext()); mockGmmMemory->setDeviceInfoResult = false; wddm->gmmMemory.reset(mockGmmMemory); wddm->init(); EXPECT_EQ(0u, mockGmmMemory->configureDeviceAddressSpaceCalled); } HWTEST_F(Wddm20WithMockGdiDllTests, givenNonGen12LPPlatformWhenConfigureDeviceAddressSpaceThenDontObtainMinAddress) { if (defaultHwInfo->platform.eRenderCoreFamily == IGFX_GEN12LP_CORE) { GTEST_SKIP(); } auto gmmMemory = new MockGmmMemoryBase(getGmmClientContext()); wddm->gmmMemory.reset(gmmMemory); wddm->init(); EXPECT_EQ(NEO::windowsMinAddress, wddm->getWddmMinAddress()); EXPECT_EQ(0u, gmmMemory->getInternalGpuVaRangeLimitCalled); } struct GdiWithMockedCloseFunc : public MockGdi { GdiWithMockedCloseFunc() : MockGdi() { closeAdapter = mockCloseAdapter; GdiWithMockedCloseFunc::closeAdapterCalled = 0u; GdiWithMockedCloseFunc::closeAdapterCalledArgPassed = 0u; } static NTSTATUS __stdcall mockCloseAdapter(IN CONST D3DKMT_CLOSEADAPTER *adapter) { closeAdapterCalled++; closeAdapterCalledArgPassed = adapter->hAdapter; return STATUS_SUCCESS; } static uint32_t closeAdapterCalled; static D3DKMT_HANDLE closeAdapterCalledArgPassed; }; uint32_t GdiWithMockedCloseFunc::closeAdapterCalled; D3DKMT_HANDLE GdiWithMockedCloseFunc::closeAdapterCalledArgPassed; TEST(HwDeviceId, whenHwDeviceIdIsDestroyedThenAdapterIsClosed) { auto gdi = std::make_unique(); auto osEnv = std::make_unique(); osEnv->gdi.reset(gdi.release()); D3DKMT_HANDLE adapter = 0x1234; { HwDeviceIdWddm hwDeviceId{adapter, {}, 1u, osEnv.get(), std::make_unique()}; } EXPECT_EQ(1u, GdiWithMockedCloseFunc::closeAdapterCalled); EXPECT_EQ(adapter, GdiWithMockedCloseFunc::closeAdapterCalledArgPassed); } namespace MockWddmResidencyLoggerFunctions { std::string recordedFileName(256, 0); FILE *testFopen(const char *filename, const char *mode) { MockWddmResidencyLoggerFunctions::recordedFileName.assign(filename); return NEO::IoFunctions::mockFopen(filename, mode); } } // namespace MockWddmResidencyLoggerFunctions struct WddmResidencyLoggerTest : public WddmTest { void SetUp() override { MockWddmResidencyLoggerFunctions::recordedFileName.clear(); WddmTest::SetUp(); NEO::IoFunctions::mockFopenCalled = 0; NEO::IoFunctions::mockVfptrinfCalled = 0; NEO::IoFunctions::mockFcloseCalled = 0; debugManager.flags.WddmResidencyLogger.set(true); mockFopenBackup = std::make_unique>(&NEO::IoFunctions::fopenPtr); NEO::IoFunctions::fopenPtr = &MockWddmResidencyLoggerFunctions::testFopen; } DebugManagerStateRestore dbgRestore; std::unique_ptr> mockFopenBackup; }; TEST_F(WddmResidencyLoggerTest, WhenResidencyLoggingEnabledThenExpectLoggerCreated) { wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); wddm->residencyLogger.reset(); if (NEO::wddmResidencyLoggingAvailable) { EXPECT_EQ(1u, NEO::IoFunctions::mockFopenCalled); EXPECT_EQ(1u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_EQ(1u, NEO::IoFunctions::mockFcloseCalled); } } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenMakeResidentSuccessThenExpectSizeRapport) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->callBaseMakeResident = true; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); D3DKMT_HANDLE handle = ALLOCATION_HANDLE; uint64_t bytesToTrim = 0; wddm->makeResident(&handle, 1, false, &bytesToTrim, 0x1000); // 2 - one for open log, second for allocation size EXPECT_EQ(2u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_TRUE(logger->makeResidentCall); EXPECT_EQ(MockGdi::pagingFenceReturnValue, logger->makeResidentPagingFence); } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenMakeResidentFailThenExpectTrimReport) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->callBaseMakeResident = true; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); D3DKMT_HANDLE handle = INVALID_HANDLE; uint64_t bytesToTrim = 0; wddm->makeResident(&handle, 1, false, &bytesToTrim, 0x1000); // 3 - one for open log, second for report allocations, 3rd for trim size EXPECT_EQ(3u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_FALSE(logger->makeResidentCall); } TEST_F(WddmTest, GivenInvalidHandleAndCantTrimFurtherSetToTrueWhenCallingMakeResidentThenFalseIsReturned) { wddm->callBaseMakeResident = true; D3DKMT_HANDLE handle = INVALID_HANDLE; uint64_t bytesToTrim = 4 * 4096; bool retVal = wddm->makeResident(&handle, 1, true, &bytesToTrim, 0x1000); EXPECT_FALSE(retVal); } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenEnterWaitCalledThenExpectInternalFlagOn) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); logger->enteredWait(); EXPECT_TRUE(logger->enterWait); } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenMakeResidentAndWaitPagingThenExpectFlagsOff) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->callBaseMakeResident = true; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); D3DKMT_HANDLE handle = ALLOCATION_HANDLE; uint64_t bytesToTrim = 0; wddm->makeResident(&handle, 1, false, &bytesToTrim, 0x1000); // 2 - one for open log, second for allocation size EXPECT_EQ(2u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_TRUE(logger->makeResidentCall); EXPECT_EQ(MockGdi::pagingFenceReturnValue, logger->makeResidentPagingFence); logger->enterWait = true; wddm->waitOnPagingFenceFromCpu(false); EXPECT_EQ(5u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_FALSE(logger->makeResidentCall); EXPECT_FALSE(logger->enterWait); EXPECT_EQ(MockGdi::pagingFenceReturnValue, logger->startWaitPagingFenceSave); } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenMakeResidentAndWaitPagingOnGpuThenExpectFlagsOff) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->callBaseMakeResident = true; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); D3DKMT_HANDLE handle = ALLOCATION_HANDLE; uint64_t bytesToTrim = 0; wddm->makeResident(&handle, 1, false, &bytesToTrim, 0x1000); // 2 - one for open log, second for allocation size EXPECT_EQ(2u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_TRUE(logger->makeResidentCall); EXPECT_EQ(MockGdi::pagingFenceReturnValue, logger->makeResidentPagingFence); logger->enterWait = true; wddm->waitOnGPU(osContext->getWddmContextHandle()); EXPECT_EQ(5u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_FALSE(logger->makeResidentCall); EXPECT_FALSE(logger->enterWait); EXPECT_EQ(MockGdi::pagingFenceReturnValue, logger->startWaitPagingFenceSave); } TEST_F(WddmResidencyLoggerTest, GivenResidencyLoggingEnabledWhenMakeResidentRequiresTrimToBudgetAndWaitPagingOnGpuThenExpectProperLoggingCount) { if (!NEO::wddmResidencyLoggingAvailable) { GTEST_SKIP(); } wddm->callBaseCreatePagingLogger = false; wddm->callBaseMakeResident = true; wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); auto logger = static_cast(wddm->residencyLogger.get()); D3DKMT_HANDLE handle = INVALID_HANDLE; uint64_t bytesToTrim = 0; wddm->makeResident(&handle, 1, false, &bytesToTrim, 0x1000); // 3 - one for open log, second for allocation size, third reporting on trim to budget EXPECT_EQ(3u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_FALSE(logger->makeResidentCall); logger->enterWait = true; wddm->waitOnGPU(osContext->getWddmContextHandle()); // additional 4 wait logs - 3 default and 1 extra for trim to budget delta time EXPECT_EQ(7u, NEO::IoFunctions::mockVfptrinfCalled); EXPECT_FALSE(logger->makeResidentCall); EXPECT_FALSE(logger->enterWait); } TEST_F(WddmResidencyLoggerTest, givenResidencyLoggingEnabledWhenDefaultDirectorySelectedThenDoNotUseDirectoryName) { std::string defaultDirectory("unk"); std::string filenameLead("pagingfence_device-0x"); wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); EXPECT_EQ(std::string::npos, MockWddmResidencyLoggerFunctions::recordedFileName.find(defaultDirectory)); EXPECT_EQ(0u, MockWddmResidencyLoggerFunctions::recordedFileName.find(filenameLead)); } TEST_F(WddmResidencyLoggerTest, givenResidencyLoggingEnabledWhenNonDefaultDirectorySelectedWithoutTrailingBackslashThenUseDirectoryNameWithAddedSlash) { std::string nonDefaultDirectory("c:\\temp\\logs"); std::string filenameLead("pagingfence_device-0x"); debugManager.flags.WddmResidencyLoggerOutputDirectory.set(nonDefaultDirectory); wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); EXPECT_EQ(0u, MockWddmResidencyLoggerFunctions::recordedFileName.find(nonDefaultDirectory)); auto backslashPos = nonDefaultDirectory.length(); auto pos = MockWddmResidencyLoggerFunctions::recordedFileName.find('\\', backslashPos); EXPECT_EQ(backslashPos, pos); auto filenameLeadPos = backslashPos + 1; EXPECT_EQ(filenameLeadPos, MockWddmResidencyLoggerFunctions::recordedFileName.find(filenameLead)); } TEST_F(WddmResidencyLoggerTest, givenResidencyLoggingEnabledWhenNonDefaultDirectorySelectedWithTrailingBackslashThenUseDirectoryNameWithoutAddingSlash) { std::string nonDefaultDirectory("c:\\temp\\logs\\"); std::string filenameLead("pagingfence_device-0x"); debugManager.flags.WddmResidencyLoggerOutputDirectory.set(nonDefaultDirectory); wddm->createPagingFenceLogger(); EXPECT_NE(nullptr, wddm->residencyLogger.get()); EXPECT_EQ(0u, MockWddmResidencyLoggerFunctions::recordedFileName.find(nonDefaultDirectory)); auto filenameLeadPos = nonDefaultDirectory.length(); EXPECT_EQ(filenameLeadPos, MockWddmResidencyLoggerFunctions::recordedFileName.find(filenameLead)); } TEST(VerifyAdapterType, whenAdapterDoesntSupportRenderThenDontCreateHwDeviceId) { auto gdi = std::make_unique(); auto osEnv = std::make_unique(); osEnv->gdi.reset(gdi.release()); LUID shadowAdapterLuid = {0xdd, 0xdd}; auto hwDeviceId = createHwDeviceIdFromAdapterLuid(*osEnv, shadowAdapterLuid, 1u); EXPECT_EQ(nullptr, hwDeviceId.get()); } TEST(VerifyAdapterType, whenAdapterSupportsRenderThenCreateHwDeviceId) { auto gdi = std::make_unique(); auto osEnv = std::make_unique(); osEnv->gdi.reset(gdi.release()); LUID adapterLuid = {0x12, 0x1234}; auto hwDeviceId = createHwDeviceIdFromAdapterLuid(*osEnv, adapterLuid, 1u); EXPECT_NE(nullptr, hwDeviceId.get()); } TEST_F(WddmTestWithMockGdiDll, givenInvalidInputwhenSettingAllocationPriorityThenFalseIsReturned) { init(); EXPECT_FALSE(wddm->setAllocationPriority(nullptr, 0, DXGI_RESOURCE_PRIORITY_MAXIMUM)); EXPECT_FALSE(wddm->setAllocationPriority(nullptr, 5, DXGI_RESOURCE_PRIORITY_MAXIMUM)); { D3DKMT_HANDLE handles[] = {ALLOCATION_HANDLE, 0}; EXPECT_FALSE(wddm->setAllocationPriority(handles, 2, DXGI_RESOURCE_PRIORITY_MAXIMUM)); } } TEST_F(WddmTestWithMockGdiDll, givenValidInputwhenSettingAllocationPriorityThenTrueIsReturned) { init(); D3DKMT_HANDLE handles[] = {ALLOCATION_HANDLE, ALLOCATION_HANDLE + 1}; EXPECT_TRUE(wddm->setAllocationPriority(handles, 2, DXGI_RESOURCE_PRIORITY_MAXIMUM)); EXPECT_EQ(static_cast(DXGI_RESOURCE_PRIORITY_MAXIMUM), getLastPriorityFcn()); EXPECT_TRUE(wddm->setAllocationPriority(handles, 2, DXGI_RESOURCE_PRIORITY_NORMAL)); EXPECT_EQ(static_cast(DXGI_RESOURCE_PRIORITY_NORMAL), getLastPriorityFcn()); } TEST_F(WddmTestWithMockGdiDll, givenQueryAdapterInfoCallReturnsSuccesThenPciBusInfoIsValid) { ADAPTER_BDF queryAdapterBDF{}; queryAdapterBDF.Bus = 1; queryAdapterBDF.Device = 2; queryAdapterBDF.Function = 3; setAdapterBDFFcn(queryAdapterBDF); EXPECT_TRUE(wddm->queryAdapterInfo()); auto pciBusInfo = wddm->getPciBusInfo(); EXPECT_EQ(pciBusInfo.pciDomain, 0u); EXPECT_EQ(pciBusInfo.pciBus, 1u); EXPECT_EQ(pciBusInfo.pciDevice, 2u); EXPECT_EQ(pciBusInfo.pciFunction, 3u); } TEST_F(WddmTestWithMockGdiDll, givenQueryAdapterInfoCallReturnsInvalidAdapterBDFThenPciBusInfoIsNotValid) { ADAPTER_BDF queryAdapterBDF{}; queryAdapterBDF.Data = std::numeric_limits::max(); setAdapterBDFFcn(queryAdapterBDF); EXPECT_TRUE(wddm->queryAdapterInfo()); auto pciBusInfo = wddm->getPciBusInfo(); EXPECT_EQ(pciBusInfo.pciDomain, PhysicalDevicePciBusInfo::invalidValue); EXPECT_EQ(pciBusInfo.pciBus, PhysicalDevicePciBusInfo::invalidValue); EXPECT_EQ(pciBusInfo.pciDevice, PhysicalDevicePciBusInfo::invalidValue); EXPECT_EQ(pciBusInfo.pciFunction, PhysicalDevicePciBusInfo::invalidValue); } TEST_F(WddmTestWithMockGdiDll, givenForceDeviceIdWhenQueryAdapterInfoThenProperDeviceID) { DebugManagerStateRestore restorer{}; debugManager.flags.ForceDeviceId.set("0x1234"); EXPECT_TRUE(wddm->queryAdapterInfo()); uint16_t expectedDeviceId = 0x1234u; EXPECT_EQ(expectedDeviceId, wddm->gfxPlatform->usDeviceID); } TEST_F(WddmTestWithMockGdiDll, givenNoMaxDualSubSlicesSupportedWhenQueryAdapterInfoThenMaxDualSubSliceIsNotSet) { HardwareInfo hwInfo = *defaultHwInfo.get(); uint32_t maxSS = 8u; hwInfo.gtSystemInfo.MaxSubSlicesSupported = maxSS; hwInfo.gtSystemInfo.MaxDualSubSlicesSupported = 0u; mockGdiDll.reset(setAdapterInfo(&hwInfo.platform, &hwInfo.gtSystemInfo, hwInfo.capabilityTable.gpuAddressSpace)); EXPECT_TRUE(wddm->queryAdapterInfo()); EXPECT_EQ(0u, wddm->getGtSysInfo()->MaxDualSubSlicesSupported); } TEST_F(WddmTestWithMockGdiDll, givenNonZeroMaxDualSubSlicesSupportedWhenQueryAdapterInfoThenNothingChanged) { HardwareInfo hwInfo = *defaultHwInfo.get(); uint32_t maxSS = 8u; uint32_t expectedMaxDSS = 6u; hwInfo.gtSystemInfo.MaxSubSlicesSupported = maxSS; hwInfo.gtSystemInfo.MaxDualSubSlicesSupported = expectedMaxDSS; mockGdiDll.reset(setAdapterInfo(&hwInfo.platform, &hwInfo.gtSystemInfo, hwInfo.capabilityTable.gpuAddressSpace)); EXPECT_TRUE(wddm->queryAdapterInfo()); EXPECT_EQ(expectedMaxDSS, wddm->getGtSysInfo()->MaxDualSubSlicesSupported); EXPECT_NE(maxSS / 2, wddm->getGtSysInfo()->MaxDualSubSlicesSupported); } struct WddmPagingFenceTest : public WddmTest { void SetUp() override { debugManager.flags.WddmPagingFenceCpuWaitDelayTime.set(WddmPagingFenceTest::defaultTestDelay); WddmTest::SetUp(); } DebugManagerStateRestore dbgRestore; static constexpr int64_t defaultTestDelay = 10; }; TEST_F(WddmPagingFenceTest, givenPagingFenceDelayNonZeroWhenCurrentPagingFenceValueNotGreaterThanPagingFenceObjectThenNoPagingFenceDelayCalled) { EXPECT_EQ(WddmPagingFenceTest::defaultTestDelay, wddm->pagingFenceDelayTime); wddm->mockPagingFence = 0u; wddm->currentPagingFenceValue = 1u; wddm->waitOnPagingFenceFromCpu(true); EXPECT_EQ(0u, wddm->delayPagingFenceFromCpuResult.called); } TEST_F(WddmPagingFenceTest, givenPagingFenceDelayNonZeroWhenCurrentPagingFenceValueGreaterThanPagingFenceObjectThenPagingFenceDelayCalled) { EXPECT_EQ(WddmPagingFenceTest::defaultTestDelay, wddm->pagingFenceDelayTime); wddm->mockPagingFence = 0u; wddm->currentPagingFenceValue = 2u; wddm->waitOnPagingFenceFromCpu(true); EXPECT_EQ(1u, wddm->delayPagingFenceFromCpuResult.called); } TEST_F(WddmPagingFenceTest, givenPagingFenceDelayZeroWhenCurrentPagingFenceValueGreaterThanPagingFenceObjectThenNoPagingFenceDelayCalled) { EXPECT_EQ(WddmPagingFenceTest::defaultTestDelay, wddm->pagingFenceDelayTime); wddm->mockPagingFence = 0u; wddm->currentPagingFenceValue = 3u; wddm->pagingFenceDelayTime = 0; wddm->waitOnPagingFenceFromCpu(true); EXPECT_EQ(0u, wddm->delayPagingFenceFromCpuResult.called); } uint64_t waitForSynchronizationObjectFromCpuCounter = 0u; uint64_t lastPassedPagingFence = 0u; NTSTATUS __stdcall waitForSynchronizationObjectFromCpuNoOpMock(const D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *waitStruct) { lastPassedPagingFence = *waitStruct->FenceValueArray; waitForSynchronizationObjectFromCpuCounter++; return STATUS_SUCCESS; } TEST_F(WddmPagingFenceTest, givenPagingFenceDelayZeroWhenCurrentPagingFenceValueGreaterAndNeededKmdWaitThenWaitForSynchronizationObjectFromCpuCalled) { EXPECT_EQ(WddmPagingFenceTest::defaultTestDelay, wddm->pagingFenceDelayTime); wddm->mockPagingFence = 0u; wddm->currentPagingFenceValue = 3u; wddm->getGdi()->waitForSynchronizationObjectFromCpu = &waitForSynchronizationObjectFromCpuNoOpMock; waitForSynchronizationObjectFromCpuCounter = 0u; wddm->waitOnPagingFenceFromCpu(true); EXPECT_EQ(lastPassedPagingFence, wddm->currentPagingFenceValue); EXPECT_EQ(1u, waitForSynchronizationObjectFromCpuCounter); } TEST_F(WddmPagingFenceTest, givenPagingFenceDelayZeroWhenCurrentPagingFenceValueGreaterAndNotNeededKmdWaitThenWaitForSynchronizationObjectFromCpuIsNotCalled) { EXPECT_EQ(WddmPagingFenceTest::defaultTestDelay, wddm->pagingFenceDelayTime); wddm->mockPagingFence = 0u; wddm->currentPagingFenceValue = 3u; wddm->getGdi()->waitForSynchronizationObjectFromCpu = &waitForSynchronizationObjectFromCpuNoOpMock; waitForSynchronizationObjectFromCpuCounter = 0u; wddm->waitOnPagingFenceFromCpu(false); EXPECT_EQ(0u, waitForSynchronizationObjectFromCpuCounter); }