feature: support for context group on Windows

Related-To: NEO-14289


Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe
2025-09-26 14:53:26 +00:00
committed by Compute-Runtime-Automation
parent 0ef032bb28
commit 98fcaf4ceb
9 changed files with 97 additions and 3 deletions

View File

@@ -105,6 +105,9 @@ class OsContext : public ReferenceTrackedObject<OsContext> {
void setContextGroupCount(uint32_t contextGroupCount) {
this->contextGroupCount = contextGroupCount;
}
uint32_t getContextGroupCount() {
return contextGroupCount;
}
bool isPartOfContextGroup() const {
return contextGroupCount > 0;
}

View File

@@ -56,7 +56,7 @@ bool OsContextWin::initializeContext(bool allocateInterrupt) {
void OsContextWin::reInitializeContext() {
NEO::EnvironmentVariableReader envReader;
bool disableContextCreationFlag = envReader.getSetting("NEO_L0_SYSMAN_NO_CONTEXT_MODE", false);
if (!disableContextCreationFlag) {
if (!disableContextCreationFlag && !isPartOfContextGroup()) {
if (contextInitialized && (false == this->wddm.skipResourceCleanup())) {
wddm.getWddmInterface()->destroyHwQueue(hardwareQueue.handle);
wddm.destroyContext(wddmContextHandle);
@@ -111,7 +111,11 @@ OsContextWin::~OsContextWin() {
if (residencyController.getMonitoredFence().fenceHandle != hardwareQueue.progressFenceHandle) {
wddm.getWddmInterface()->destroyMonitorFence(residencyController.getMonitoredFence().fenceHandle);
}
wddm.destroyContext(wddmContextHandle);
if (!isPartOfContextGroup() ||
(isPartOfContextGroup() && getPrimaryContext() == nullptr)) {
wddm.destroyContext(wddmContextHandle);
}
}
}

View File

@@ -208,4 +208,5 @@ inline void propagateData(ADAPTER_INFO_KMD &adapterInfo) {
base.WaTable = adapterInfo.WaTable;
base.GfxPlatform = adapterInfo.GfxPlatform;
}
struct CREATEHWQUEUE_PVTDATA {}; // NOLINT(readability-identifier-naming)
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -21,4 +21,9 @@ CREATECONTEXT_PVTDATA initPrivateData(OsContextWin &osContext) {
return privateData;
}
CREATEHWQUEUE_PVTDATA initHwQueuePrivateData(OsContextWin &osContext) {
CREATEHWQUEUE_PVTDATA privateData = {};
return privateData;
}
} // namespace NEO

View File

@@ -1011,6 +1011,11 @@ bool Wddm::setLowPriorityContextParam(D3DKMT_HANDLE contextHandle) {
}
bool Wddm::createContext(OsContextWin &osContext) {
if (osContext.isPartOfContextGroup() && osContext.getPrimaryContext() != nullptr && wddmInterface->hwQueuesSupported()) {
osContext.setWddmContextHandle(static_cast<const OsContextWin *>(osContext.getPrimaryContext())->getWddmContextHandle());
return true;
}
NTSTATUS status = STATUS_UNSUCCESSFUL;
D3DKMT_CREATECONTEXTVIRTUAL createContext = {};

View File

@@ -47,6 +47,7 @@ enum class HeapIndex : uint32_t;
unsigned int readEnablePreemptionRegKey();
bool isShutdownInProgress();
CREATECONTEXT_PVTDATA initPrivateData(OsContextWin &osContext);
CREATEHWQUEUE_PVTDATA initHwQueuePrivateData(OsContextWin &osContext);
class Wddm : public DriverModel {
public:

View File

@@ -105,11 +105,18 @@ bool NEO::WddmInterface20::createFenceForDirectSubmission(MonitoredFence &monito
bool WddmInterface23::createHwQueue(OsContextWin &osContext) {
D3DKMT_CREATEHWQUEUE createHwQueue = {};
CREATEHWQUEUE_PVTDATA hwQueuePrivateData = {};
if (!wddm.getGdi()->setupHwQueueProcAddresses()) {
return false;
}
if (osContext.isPartOfContextGroup()) {
hwQueuePrivateData = initHwQueuePrivateData(osContext);
createHwQueue.pPrivateDriverData = &hwQueuePrivateData;
createHwQueue.PrivateDriverDataSize = sizeof(hwQueuePrivateData);
}
createHwQueue.hHwContext = osContext.getWddmContextHandle();
if (osContext.getPreemptionMode() >= PreemptionMode::MidBatch) {
createHwQueue.Flags.DisableGpuTimeout = wddm.getEnablePreemptionRegValue();

View File

@@ -601,6 +601,7 @@ NTSTATUS __stdcall mockD3DKMTSetAllocationPriority(IN CONST D3DKMT_SETALLOCATION
}
static D3DKMT_CREATEHWQUEUE createHwQueueData{};
static CREATEHWQUEUE_PVTDATA createHwQueuePrivateData{};
NTSTATUS __stdcall mockD3DKMTCreateHwQueue(IN OUT D3DKMT_CREATEHWQUEUE *createHwQueue) {
createHwQueue->hHwQueueProgressFence = 1;
@@ -608,6 +609,11 @@ NTSTATUS __stdcall mockD3DKMTCreateHwQueue(IN OUT D3DKMT_CREATEHWQUEUE *createHw
createHwQueue->HwQueueProgressFenceGPUVirtualAddress = 3;
createHwQueue->hHwQueue = 4;
createHwQueueData = *createHwQueue;
if (createHwQueue->PrivateDriverDataSize == sizeof(CREATEHWQUEUE_PVTDATA) && createHwQueue->pPrivateDriverData) {
createHwQueuePrivateData = *((CREATEHWQUEUE_PVTDATA *)createHwQueue->pPrivateDriverData);
createHwQueueData.pPrivateDriverData = &createHwQueuePrivateData;
}
return STATUS_SUCCESS;
}
@@ -615,6 +621,8 @@ static D3DKMT_DESTROYHWQUEUE destroyHwQueueData{};
NTSTATUS __stdcall mockD3DKMTDestroyHwQueue(IN CONST D3DKMT_DESTROYHWQUEUE *destroyHwQueue) {
destroyHwQueueData = *destroyHwQueue;
createHwQueueData.pPrivateDriverData = nullptr;
createHwQueueData.PrivateDriverDataSize = 0;
return STATUS_SUCCESS;
}

View File

@@ -246,3 +246,63 @@ TEST_F(Wddm23TestsWithoutWddmInit, givenFailureOnGdiInitializationWhenCreatingHw
EXPECT_EQ(1u, wddmMockInterface->createHwQueueCalled);
EXPECT_FALSE(wddmMockInterface->createHwQueueResult);
}
TEST_F(Wddm23TestsWithoutWddmInit, givenContextGroupWhenContextFromContextGroupCreatedThenItHasPrimaryContextHandle) {
if (defaultHwInfo->capabilityTable.defaultEngineType != aub_stream::EngineType::ENGINE_CCS) {
GTEST_SKIP();
}
DebugManagerStateRestore retore;
debugManager.flags.ContextGroupSize.set(4);
wddmMockInterface = static_cast<WddmMockInterface23 *>(wddm->wddmInterface.release());
wddm->init();
wddm->wddmInterface.reset(wddmMockInterface);
EngineTypeUsage engineUsage = {};
engineUsage.first = aub_stream::EngineType::ENGINE_CCS;
engineUsage.second = EngineUsage::regular;
osContext = std::make_unique<OsContextWin>(*wddm, 0, 0u,
EngineDescriptorHelper::getDefaultDescriptor(engineUsage));
EXPECT_TRUE(osContext->ensureContextInitialized(false));
EXPECT_EQ(1u, wddmMockInterface->createHwQueueCalled);
auto osContext2 = std::make_unique<OsContextWin>(*wddm, 0, 1u,
EngineDescriptorHelper::getDefaultDescriptor(engineUsage));
osContext2->setPrimaryContext(osContext.get());
EXPECT_TRUE(osContext2->ensureContextInitialized(false));
EXPECT_EQ(osContext->getWddmContextHandle(), osContext2->getWddmContextHandle());
EXPECT_EQ(getCreateHwQueueData()->hHwContext, osContext->getWddmContextHandle());
}
TEST_F(Wddm23TestsWithoutWddmInit, givenContextGroupWhenContextFromContextGroupDestroyedThenPrimaryContextHandleIsDestroyedOnce) {
if (defaultHwInfo->capabilityTable.defaultEngineType != aub_stream::EngineType::ENGINE_CCS) {
GTEST_SKIP();
}
DebugManagerStateRestore retore;
debugManager.flags.ContextGroupSize.set(4);
wddmMockInterface = static_cast<WddmMockInterface23 *>(wddm->wddmInterface.release());
wddm->init();
wddm->wddmInterface.reset(wddmMockInterface);
{
EngineTypeUsage engineUsage = {};
engineUsage.first = aub_stream::EngineType::ENGINE_CCS;
engineUsage.second = EngineUsage::regular;
osContext = std::make_unique<OsContextWin>(*wddm, 0, 0u,
EngineDescriptorHelper::getDefaultDescriptor(engineUsage));
EXPECT_TRUE(osContext->ensureContextInitialized(false));
auto osContext2 = std::make_unique<OsContextWin>(*wddm, 0, 1u,
EngineDescriptorHelper::getDefaultDescriptor(engineUsage));
osContext2->setPrimaryContext(osContext.get());
EXPECT_TRUE(osContext2->ensureContextInitialized(false));
}
EXPECT_EQ(1u, wddm->destroyContextResult.called);
}