diff --git a/shared/source/os_interface/windows/wddm/helper_drm_or_wddm.cpp b/shared/source/os_interface/windows/wddm/helper_drm_or_wddm.cpp index a594cb2525..974c636d7a 100644 --- a/shared/source/os_interface/windows/wddm/helper_drm_or_wddm.cpp +++ b/shared/source/os_interface/windows/wddm/helper_drm_or_wddm.cpp @@ -12,7 +12,10 @@ namespace NEO { NTSTATUS Wddm::createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHandle) { return getGdi()->shareObjects(1, resourceHandle, nullptr, SHARED_ALLOCATION_WRITE, ntHandle); } -bool Wddm::getReadOnlyFlagValue(const void *alignedCpuPtr) const { +bool Wddm::getReadOnlyFlagValue(const void *cpuPtr) const { + return false; +} +bool Wddm::isReadOnlyFlagFallbackSupported() const { return false; } } // namespace NEO \ No newline at end of file diff --git a/shared/source/os_interface/windows/wddm/helper_wddm.cpp b/shared/source/os_interface/windows/wddm/helper_wddm.cpp index 03548eb43e..48ee720223 100644 --- a/shared/source/os_interface/windows/wddm/helper_wddm.cpp +++ b/shared/source/os_interface/windows/wddm/helper_wddm.cpp @@ -17,7 +17,10 @@ NTSTATUS Wddm::createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHan return getGdi()->shareObjects(1, resourceHandle, &objAttr, SHARED_ALLOCATION_WRITE, ntHandle); } -bool Wddm::getReadOnlyFlagValue(const void *alignedCpuPtr) const { - return alignedCpuPtr != nullptr; +bool Wddm::getReadOnlyFlagValue(const void *cpuPtr) const { + return !isAligned(cpuPtr); +} +bool Wddm::isReadOnlyFlagFallbackSupported() const { + return true; } } // namespace NEO diff --git a/shared/source/os_interface/windows/wddm/wddm.cpp b/shared/source/os_interface/windows/wddm/wddm.cpp index e97ab37b90..467d08dc3a 100644 --- a/shared/source/os_interface/windows/wddm/wddm.cpp +++ b/shared/source/os_interface/windows/wddm/wddm.cpp @@ -650,7 +650,11 @@ bool Wddm::freeGpuVirtualAddress(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size) return status == STATUS_SUCCESS; } -NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle) { +bool Wddm::isReadOnlyFlagFallbackAvailable(const D3DKMT_CREATEALLOCATION &createAllocation) const { + return isReadOnlyFlagFallbackSupported() && createAllocation.pAllocationInfo2->pSystemMem && !createAllocation.Flags.ReadOnly; +} + +NTSTATUS Wddm::createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle) { NTSTATUS status = STATUS_UNSUCCESSFUL; D3DDDI_ALLOCATIONINFO2 allocationInfo = {}; D3DKMT_CREATEALLOCATION createAllocation = {}; @@ -658,14 +662,14 @@ NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKM if (gmm == nullptr) return false; - allocationInfo.pSystemMem = alignedCpuPtr; + allocationInfo.pSystemMem = gmm->gmmResourceInfo->getSystemMemPointer(); allocationInfo.pPrivateDriverData = gmm->gmmResourceInfo->peekHandle(); allocationInfo.PrivateDriverDataSize = static_cast(gmm->gmmResourceInfo->peekHandleSize()); createAllocation.NumAllocations = 1; createAllocation.Flags.CreateShared = outSharedHandle ? TRUE : FALSE; createAllocation.Flags.NtSecuritySharing = outSharedHandle ? TRUE : FALSE; createAllocation.Flags.CreateResource = outSharedHandle ? TRUE : FALSE; - createAllocation.Flags.ReadOnly = getReadOnlyFlagValue(alignedCpuPtr); + createAllocation.Flags.ReadOnly = getReadOnlyFlagValue(cpuPtr); createAllocation.pAllocationInfo2 = &allocationInfo; createAllocation.hDevice = device; @@ -678,6 +682,10 @@ NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKM } status = getGdi()->createAllocation2(&createAllocation); + if (status != STATUS_SUCCESS && isReadOnlyFlagFallbackAvailable(createAllocation)) { + createAllocation.Flags.ReadOnly = TRUE; + status = getGdi()->createAllocation2(&createAllocation); + } if (status != STATUS_SUCCESS) { DEBUG_BREAK_IF(true); return status; @@ -778,6 +786,10 @@ NTSTATUS Wddm::createAllocationsAndMapGpuVa(OsHandleStorage &osHandles) { while (status == STATUS_UNSUCCESSFUL) { status = getGdi()->createAllocation2(&createAllocation); + if (status != STATUS_SUCCESS && isReadOnlyFlagFallbackAvailable(createAllocation)) { + createAllocation.Flags.ReadOnly = TRUE; + status = getGdi()->createAllocation2(&createAllocation); + } if (status != STATUS_SUCCESS) { PRINT_DEBUG_STRING(debugManager.flags.PrintDebugMessages.get(), stderr, "%s status: %d", __FUNCTION__, status); diff --git a/shared/source/os_interface/windows/wddm/wddm.h b/shared/source/os_interface/windows/wddm/wddm.h index edbdee18df..c832c5c309 100644 --- a/shared/source/os_interface/windows/wddm/wddm.h +++ b/shared/source/os_interface/windows/wddm/wddm.h @@ -73,7 +73,7 @@ class Wddm : public DriverModel { MOCKABLE_VIRTUAL void applyAdditionalMapGPUVAFields(D3DDDI_MAPGPUVIRTUALADDRESS &mapGPUVA, Gmm *gmm, AllocationType type); MOCKABLE_VIRTUAL uint64_t freeGmmGpuVirtualAddress(Gmm *gmm, D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size); MOCKABLE_VIRTUAL bool freeGpuVirtualAddress(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size); - MOCKABLE_VIRTUAL NTSTATUS createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle); + MOCKABLE_VIRTUAL NTSTATUS createAllocation(const void *cpuPtr, const Gmm *gmm, D3DKMT_HANDLE &outHandle, D3DKMT_HANDLE &outResourceHandle, uint64_t *outSharedHandle); MOCKABLE_VIRTUAL bool createAllocation(const Gmm *gmm, D3DKMT_HANDLE &outHandle); MOCKABLE_VIRTUAL NTSTATUS createAllocationsAndMapGpuVa(OsHandleStorage &osHandles); MOCKABLE_VIRTUAL bool destroyAllocations(const D3DKMT_HANDLE *handles, uint32_t allocationCount, D3DKMT_HANDLE resourceHandle); @@ -257,7 +257,9 @@ class Wddm : public DriverModel { void setNewResourceBoundToPageTable(); void setProcessPowerThrottling(); void setThreadPriority(); - bool getReadOnlyFlagValue(const void *alignedCpuPtr) const; + bool getReadOnlyFlagValue(const void *cpuPtr) const; + bool isReadOnlyFlagFallbackSupported() const; + bool isReadOnlyFlagFallbackAvailable(const D3DKMT_CREATEALLOCATION &createAllocation) const; GMM_GFX_PARTITIONING gfxPartition{}; ADAPTER_BDF adapterBDF{}; diff --git a/shared/source/os_interface/windows/wddm_memory_manager.cpp b/shared/source/os_interface/windows/wddm_memory_manager.cpp index 59c461c1f9..c69c0852a5 100644 --- a/shared/source/os_interface/windows/wddm_memory_manager.cpp +++ b/shared/source/os_interface/windows/wddm_memory_manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2024 Intel Corporation + * Copyright (C) 2018-2025 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -1132,10 +1132,10 @@ bool WddmMemoryManager::mapMultiHandleAllocationWithRetry(WddmAllocation *alloca bool WddmMemoryManager::createGpuAllocationsWithRetry(WddmAllocation *allocation) { for (auto handleId = 0u; handleId < allocation->getNumGmms(); handleId++) { auto gmm = allocation->getGmm(handleId); - auto status = getWddm(allocation->getRootDeviceIndex()).createAllocation(gmm->gmmResourceInfo->getSystemMemPointer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify()); + auto status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify()); if (status == STATUS_GRAPHICS_NO_VIDEO_MEMORY && deferredDeleter) { deferredDeleter->drain(true, false); - status = getWddm(allocation->getRootDeviceIndex()).createAllocation(gmm->gmmResourceInfo->getSystemMemPointer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify()); + status = getWddm(allocation->getRootDeviceIndex()).createAllocation(allocation->getUnderlyingBuffer(), gmm, allocation->getHandleToModify(handleId), allocation->getResourceHandleToModify(), allocation->getSharedHandleToModify()); } if (status != STATUS_SUCCESS) { getWddm(allocation->getRootDeviceIndex()).destroyAllocations(&allocation->getHandles()[0], handleId, allocation->getResourceHandle()); diff --git a/shared/test/common/mock_gdi/mock_gdi.cpp b/shared/test/common/mock_gdi/mock_gdi.cpp index a2a71419c6..b063a8f296 100644 --- a/shared/test/common/mock_gdi/mock_gdi.cpp +++ b/shared/test/common/mock_gdi/mock_gdi.cpp @@ -159,6 +159,7 @@ inline void *getStaticStorage(uint32_t slot) { static D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; static bool captureCreateAllocationFlags = false; static uint32_t createAllocation2NumCalled = 0; +static bool supportCreateAllocationWithReadWriteExisitingSysMemory = true; void setCapturingCreateAllocationFlags() { captureCreateAllocationFlags = true; @@ -171,6 +172,11 @@ void getCapturedCreateAllocationFlags(D3DKMT_CREATEALLOCATIONFLAGS &capturedCrea captureCreateAllocationFlags = false; } +void setSupportCreateAllocationWithReadWriteExisitingSysMemory(bool supportValue, bool &previousValue) { + previousValue = supportCreateAllocationWithReadWriteExisitingSysMemory; + supportCreateAllocationWithReadWriteExisitingSysMemory = supportValue; +} + NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *allocation) { D3DDDI_ALLOCATIONINFO2 *allocationInfo; int numOfAllocations; @@ -189,7 +195,6 @@ NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *a if (captureCreateAllocationFlags) { createAllocationFlags = pallocation.Flags; createAllocation2NumCalled++; - return STATUS_SUCCESS; } numOfAllocations = allocation->NumAllocations; @@ -210,6 +215,9 @@ NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *a static uint32_t handleIdForStaticStorage = 1u; static uint32_t handleIdForUserPtr = ALLOCATION_HANDLE + 1u; if (allocationInfo->pSystemMem) { + if (!supportCreateAllocationWithReadWriteExisitingSysMemory && !createAllocationFlags.ReadOnly) { + return STATUS_GRAPHICS_NO_VIDEO_MEMORY; + } userPtrMap.insert({handleIdForUserPtr, const_cast(allocationInfo->pSystemMem)}); allocationInfo->hAllocation = handleIdForUserPtr; handleIdForUserPtr++; diff --git a/shared/test/common/mock_gdi/mock_gdi.h b/shared/test/common/mock_gdi/mock_gdi.h index fd35157eba..6c60fa7c21 100644 --- a/shared/test/common/mock_gdi/mock_gdi.h +++ b/shared/test/common/mock_gdi/mock_gdi.h @@ -111,3 +111,4 @@ void setMockGetDeviceStateReturnValue(NTSTATUS newReturnValue, bool execution); void initGfxPartition(); void setCapturingCreateAllocationFlags(); void getCapturedCreateAllocationFlags(D3DKMT_CREATEALLOCATIONFLAGS &capturedCreateAllocationFlags, uint32_t &numCalled); +void setSupportCreateAllocationWithReadWriteExisitingSysMemory(bool supportValue, bool &previousValue); diff --git a/shared/test/common/mock_gdi/mock_os_library.cpp b/shared/test/common/mock_gdi/mock_os_library.cpp index 3e5d9f70a5..97043e4bea 100644 --- a/shared/test/common/mock_gdi/mock_os_library.cpp +++ b/shared/test/common/mock_gdi/mock_os_library.cpp @@ -259,6 +259,9 @@ void *MockOsLibrary::getProcAddress(const std::string &procName) { if (procName == "getCapturedCreateAllocationFlags") { return reinterpret_cast(getCapturedCreateAllocationFlags); } + if (procName == "setSupportCreateAllocationWithReadWriteExisitingSysMemory") { + return reinterpret_cast(setSupportCreateAllocationWithReadWriteExisitingSysMemory); + } return nullptr; } diff --git a/shared/test/common/mocks/mock_wddm.h b/shared/test/common/mocks/mock_wddm.h index fd46c39946..945869e549 100644 --- a/shared/test/common/mocks/mock_wddm.h +++ b/shared/test/common/mocks/mock_wddm.h @@ -54,6 +54,8 @@ class WddmMock : public Wddm { using Wddm::gfxWorkaroundTable; using Wddm::gmmMemory; using Wddm::hwDeviceId; + using Wddm::isReadOnlyFlagFallbackAvailable; + using Wddm::isReadOnlyFlagFallbackSupported; using Wddm::mapGpuVirtualAddress; using Wddm::minAddress; using Wddm::pagingFenceAddress; diff --git a/shared/test/common/os_interface/windows/gdi_dll_fixture.h b/shared/test/common/os_interface/windows/gdi_dll_fixture.h index 2ecc2bebf0..d7f253b8d4 100644 --- a/shared/test/common/os_interface/windows/gdi_dll_fixture.h +++ b/shared/test/common/os_interface/windows/gdi_dll_fixture.h @@ -63,6 +63,7 @@ struct GdiDllFixture { setMockGetDeviceStateReturnValueFcn = reinterpret_cast(mockGdiDll->getProcAddress("setMockGetDeviceStateReturnValue")); getCapturedCreateAllocationFlagsFcn = reinterpret_cast(mockGdiDll->getProcAddress("getCapturedCreateAllocationFlags")); setCapturingCreateAllocationFlagsFcn = reinterpret_cast(mockGdiDll->getProcAddress("setCapturingCreateAllocationFlags")); + setSupportCreateAllocationWithReadWriteExisitingSysMemoryFcn = reinterpret_cast(mockGdiDll->getProcAddress("setSupportCreateAllocationWithReadWriteExisitingSysMemory")); setMockLastDestroyedResHandleFcn((D3DKMT_HANDLE)0); *getDestroySynchronizationObjectDataFcn() = {}; *getCreateSynchronizationObject2FailCallFcn() = false; @@ -113,4 +114,5 @@ struct GdiDllFixture { decltype(&setMockGetDeviceStateReturnValue) setMockGetDeviceStateReturnValueFcn = nullptr; decltype(&setCapturingCreateAllocationFlags) setCapturingCreateAllocationFlagsFcn = nullptr; decltype(&getCapturedCreateAllocationFlags) getCapturedCreateAllocationFlagsFcn = nullptr; + decltype(&setSupportCreateAllocationWithReadWriteExisitingSysMemory) setSupportCreateAllocationWithReadWriteExisitingSysMemoryFcn = nullptr; }; diff --git a/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp b/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp index f98203b8fc..44fa3d5bbb 100644 --- a/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp +++ b/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp @@ -66,6 +66,7 @@ struct MockWddmLinux : NEO::Wddm { using Wddm::gfxPartition; using Wddm::gfxPlatform; using Wddm::gmmMemory; + using Wddm::isReadOnlyFlagFallbackSupported; }; struct MockGmmMemoryWddmLinux : NEO::GmmMemory { @@ -803,6 +804,9 @@ TEST_F(WddmLinuxTest, whenGettingReadOnlyFlagThenAlwaysReturnFalse) { EXPECT_FALSE(wddm->getReadOnlyFlagValue(nullptr)); } +TEST_F(WddmLinuxTest, whenGettingReadOnlyFlagFallbackSupportThenFalseIsReturned) { + EXPECT_FALSE(wddm->isReadOnlyFlagFallbackSupported()); +} class MockOsTimeLinux : public NEO::OSTimeLinux { public: MockOsTimeLinux(NEO::OSInterface &osInterface, std::unique_ptr deviceTime) : NEO::OSTimeLinux(osInterface, std::move(deviceTime)) {} diff --git a/shared/test/unit_test/os_interface/windows/wddm_tests.cpp b/shared/test/unit_test/os_interface/windows/wddm_tests.cpp index 673e21c53b..512cc1e75b 100644 --- a/shared/test/unit_test/os_interface/windows/wddm_tests.cpp +++ b/shared/test/unit_test/os_interface/windows/wddm_tests.cpp @@ -1001,33 +1001,89 @@ TEST_F(WddmTests, whenInitializeFailureThenInitOsInterfaceWddmFails) { EXPECT_FALSE(rootDeviceEnvironment->initOsInterface(std::move(hwDeviceId), 0u)); } -TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationThenAllocationCreatedWithReadOnlyFlagPassed) { +TEST_F(WddmTests, givenPageMisalignedHostMemoryPassedToCreateAllocationThenAllocationCreatedWithReadOnlyFlagPassed) { wddm->init(); setCapturingCreateAllocationFlagsFcn(); - static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + void *pageMisalignedPtr = reinterpret_cast(MemoryConstants::pageSize + MemoryConstants::cacheLineSize); D3DKMT_HANDLE handle, resHandle; GmmRequirements gmmRequirements{}; - Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), constMem, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); - EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocation(constMem, &gmm, handle, resHandle, nullptr)); + EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocation(pageMisalignedPtr, &gmm, handle, resHandle, nullptr)); D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; uint32_t createAllocation2NumCalled = 0; getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); - EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(constMem)); + EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(pageMisalignedPtr)); EXPECT_EQ(1u, createAllocation2NumCalled); + EXPECT_TRUE(wddm->destroyAllocations(&handle, 1, resHandle)); } -TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithReadOnlyFlagPassed) { +TEST_F(WddmTests, givenPageAlignedReadWriteHostMemoryPassedToCreateAllocationThenAllocationCreatedWithoutReadOnlyFlagPassed) { + wddm->init(); + setCapturingCreateAllocationFlagsFcn(); + + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + + D3DKMT_HANDLE handle, resHandle; + GmmRequirements gmmRequirements{}; + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + + EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocation(pageAlignedPtr, &gmm, handle, resHandle, nullptr)); + D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; + uint32_t createAllocation2NumCalled = 0; + getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); + EXPECT_FALSE(createAllocationFlags.ReadOnly); + EXPECT_EQ(1u, createAllocation2NumCalled); + EXPECT_TRUE(wddm->destroyAllocations(&handle, 1, resHandle)); +} + +TEST_F(WddmTests, givenPageAlignedReadOnlyHostMemoryPassedToCreateAllocationWhenReadOnlyFallbackIsSupportedThenAllocationCreatedWithReadOnlyFlagPassedOtherwiseAllocationFails) { + wddm->init(); + setCapturingCreateAllocationFlagsFcn(); + + bool readOnlyFallbackSupported = wddm->isReadOnlyFlagFallbackSupported(); + bool readWriteExistingSysMemSupported{}; + setSupportCreateAllocationWithReadWriteExisitingSysMemory(false, readWriteExistingSysMemSupported); + + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + + D3DKMT_HANDLE handle, resHandle; + GmmRequirements gmmRequirements{}; + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + + auto allocationStatus = wddm->createAllocation(pageAlignedPtr, &gmm, handle, resHandle, nullptr); + D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; + uint32_t createAllocation2NumCalled = 0; + getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); + + if (readOnlyFallbackSupported) { + EXPECT_EQ(STATUS_SUCCESS, allocationStatus); + EXPECT_TRUE(createAllocationFlags.ReadOnly); + EXPECT_EQ(2u, createAllocation2NumCalled); + EXPECT_TRUE(wddm->destroyAllocations(&handle, 1, resHandle)); + } else { + EXPECT_EQ(STATUS_GRAPHICS_NO_VIDEO_MEMORY, allocationStatus); + EXPECT_FALSE(createAllocationFlags.ReadOnly); + EXPECT_EQ(1u, createAllocation2NumCalled); + } + bool readWriteExistingSysMemSupportedForTest{}; + setSupportCreateAllocationWithReadWriteExisitingSysMemory(readWriteExistingSysMemSupported, readWriteExistingSysMemSupportedForTest); + EXPECT_FALSE(readWriteExistingSysMemSupportedForTest); +} + +TEST_F(WddmTests, givenPageMisalignedMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithReadOnlyFlagPassed) { wddm->init(); wddm->callBaseMapGpuVa = false; setCapturingCreateAllocationFlagsFcn(); - static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + void *pageMisalignedPtr = reinterpret_cast(MemoryConstants::pageSize + MemoryConstants::cacheLineSize); GmmRequirements gmmRequirements{}; - Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), constMem, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); OsHandleStorage handleStorage; OsHandleWin osHandle; @@ -1035,7 +1091,7 @@ TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocat ResidencyData residency(maxOsContextCount); handleStorage.fragmentCount = 1; - handleStorage.fragmentStorageData[0].cpuPtr = constMem; + handleStorage.fragmentStorageData[0].cpuPtr = pageMisalignedPtr; handleStorage.fragmentStorageData[0].fragmentSize = 10; handleStorage.fragmentStorageData[0].freeTheFragment = false; handleStorage.fragmentStorageData[0].osHandleStorage = &osHandle; @@ -1046,7 +1102,123 @@ TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocat D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; uint32_t createAllocation2NumCalled = 0; getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); - EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(constMem)); + EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(pageMisalignedPtr)); EXPECT_EQ(1u, createAllocation2NumCalled); + auto allocationHandle = static_cast(handleStorage.fragmentStorageData[0].osHandleStorage)->handle; + EXPECT_TRUE(wddm->destroyAllocations(&allocationHandle, 1, 0)); +} + +TEST_F(WddmTests, givenPageAlignedReadWriteMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithoutReadOnlyFlagPassed) { + wddm->init(); + wddm->callBaseMapGpuVa = false; + setCapturingCreateAllocationFlagsFcn(); + + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + + GmmRequirements gmmRequirements{}; + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + + OsHandleStorage handleStorage; + OsHandleWin osHandle; + auto maxOsContextCount = 1u; + ResidencyData residency(maxOsContextCount); + + handleStorage.fragmentCount = 1; + handleStorage.fragmentStorageData[0].cpuPtr = pageAlignedPtr; + handleStorage.fragmentStorageData[0].fragmentSize = 10; + handleStorage.fragmentStorageData[0].freeTheFragment = false; + handleStorage.fragmentStorageData[0].osHandleStorage = &osHandle; + handleStorage.fragmentStorageData[0].residency = &residency; + osHandle.gmm = &gmm; + + EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocationsAndMapGpuVa(handleStorage)); + D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; + uint32_t createAllocation2NumCalled = 0; + getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); + EXPECT_FALSE(createAllocationFlags.ReadOnly); + EXPECT_EQ(1u, createAllocation2NumCalled); + auto allocationHandle = static_cast(handleStorage.fragmentStorageData[0].osHandleStorage)->handle; + EXPECT_TRUE(wddm->destroyAllocations(&allocationHandle, 1, 0)); +} + +TEST_F(WddmTests, givenPageAlignedReadOnlyMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithReadOnlyFlagPassedOtherwiseAllocationFails) { + wddm->init(); + wddm->callBaseMapGpuVa = false; + setCapturingCreateAllocationFlagsFcn(); + + bool readOnlyFallbackSupported = wddm->isReadOnlyFlagFallbackSupported(); + bool readWriteExistingSysMemSupported{}; + setSupportCreateAllocationWithReadWriteExisitingSysMemory(false, readWriteExistingSysMemSupported); + + void *pageAlignedPtr = reinterpret_cast(MemoryConstants::pageSize); + + GmmRequirements gmmRequirements{}; + Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), pageAlignedPtr, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements); + + OsHandleStorage handleStorage; + OsHandleWin osHandle; + auto maxOsContextCount = 1u; + ResidencyData residency(maxOsContextCount); + + handleStorage.fragmentCount = 1; + handleStorage.fragmentStorageData[0].cpuPtr = pageAlignedPtr; + handleStorage.fragmentStorageData[0].fragmentSize = 10; + handleStorage.fragmentStorageData[0].freeTheFragment = false; + handleStorage.fragmentStorageData[0].osHandleStorage = &osHandle; + handleStorage.fragmentStorageData[0].residency = &residency; + osHandle.gmm = &gmm; + + auto allocationStatus = wddm->createAllocationsAndMapGpuVa(handleStorage); + D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{}; + uint32_t createAllocation2NumCalled = 0; + getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled); + + if (readOnlyFallbackSupported) { + EXPECT_EQ(STATUS_SUCCESS, allocationStatus); + EXPECT_TRUE(createAllocationFlags.ReadOnly); + EXPECT_EQ(2u, createAllocation2NumCalled); + auto allocationHandle = static_cast(handleStorage.fragmentStorageData[0].osHandleStorage)->handle; + EXPECT_TRUE(wddm->destroyAllocations(&allocationHandle, 1, 0)); + } else { + EXPECT_EQ(STATUS_GRAPHICS_NO_VIDEO_MEMORY, allocationStatus); + EXPECT_FALSE(createAllocationFlags.ReadOnly); + EXPECT_EQ(1u, createAllocation2NumCalled); + } + + bool readWriteExistingSysMemSupportedForTest{}; + setSupportCreateAllocationWithReadWriteExisitingSysMemory(readWriteExistingSysMemSupported, readWriteExistingSysMemSupportedForTest); + EXPECT_FALSE(readWriteExistingSysMemSupportedForTest); +} + +TEST_F(WddmTests, whenThereIsNoExisitngSysMemoryThenReadOnlyFallbackIsNotAvailable) { + D3DKMT_CREATEALLOCATION createAllocation{}; + D3DDDI_ALLOCATIONINFO2 allocationInfo2{}; + createAllocation.pAllocationInfo2 = &allocationInfo2; + allocationInfo2.pSystemMem = nullptr; + + EXPECT_FALSE(wddm->isReadOnlyFlagFallbackAvailable(createAllocation)); +} + +TEST_F(WddmTests, givenReadOnlyFlagAlreadySetInCreateAllocationFlagsThenReadOnlyFallbackIsNotAvailable) { + D3DKMT_CREATEALLOCATION createAllocation{}; + D3DDDI_ALLOCATIONINFO2 allocationInfo2{}; + createAllocation.pAllocationInfo2 = &allocationInfo2; + + allocationInfo2.pSystemMem = reinterpret_cast(MemoryConstants::pageSize); + createAllocation.Flags.ReadOnly = true; + + EXPECT_FALSE(wddm->isReadOnlyFlagFallbackAvailable(createAllocation)); +} + +TEST_F(WddmTests, givenSysMemoryPointerAndReadOnlyFlagNotSetInCreateAllocationFlagsThenReadOnlyFallbackIsAvailableBasedOnFallbackSupport) { + D3DKMT_CREATEALLOCATION createAllocation{}; + D3DDDI_ALLOCATIONINFO2 allocationInfo2{}; + createAllocation.pAllocationInfo2 = &allocationInfo2; + + allocationInfo2.pSystemMem = reinterpret_cast(MemoryConstants::pageSize); + createAllocation.Flags.ReadOnly = false; + + auto readOnlyFallbackSupported = wddm->isReadOnlyFlagFallbackSupported(); + EXPECT_EQ(readOnlyFallbackSupported, wddm->isReadOnlyFlagFallbackAvailable(createAllocation)); } } // namespace NEO diff --git a/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp b/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp index c034a32661..34446104b4 100644 --- a/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp +++ b/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp @@ -406,9 +406,16 @@ TEST_F(WddmTestWithMockGdiDll, givenSetThreadPriorityStateEnabledWhenInitWddmThe EXPECT_EQ(SysCalls::ThreadPriority::AboveNormal, SysCalls::setThreadPriorityLastValue); } -TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagThenReturnTrueOnlyForCpuPointer) { - void *ptr = reinterpret_cast(0x1000); - EXPECT_TRUE(wddm->getReadOnlyFlagValue(ptr)); +TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagThenReturnTrueOnlyForPageMisaligedCpuPointer) { + void *alignedPtr = reinterpret_cast(MemoryConstants::pageSize); + EXPECT_FALSE(wddm->getReadOnlyFlagValue(alignedPtr)); + + void *misalignedPtr = reinterpret_cast(MemoryConstants::pageSize + MemoryConstants::cacheLineSize); + EXPECT_TRUE(wddm->getReadOnlyFlagValue(misalignedPtr)); EXPECT_FALSE(wddm->getReadOnlyFlagValue(nullptr)); } + +TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagFallbackSupportThenTrueIsReturned) { + EXPECT_TRUE(wddm->isReadOnlyFlagFallbackSupported()); +}