/* * Copyright (C) 2025 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/os_interface/windows/external_semaphore_windows.h" #include "shared/source/os_interface/os_library.h" #include "shared/source/os_interface/windows/d3dkmthk_wrapper.h" #include "shared/source/os_interface/windows/gdi_interface.h" #include "shared/source/os_interface/windows/wddm/wddm.h" #include "shared/source/os_interface/windows/windows_wrapper.h" #include typedef VOID(NTAPI *_RtlInitUnicodeString)(PUNICODE_STRING destinationString, PCWSTR sourceString); typedef VOID(NTAPI *_NtOpenDirectoryObject)(PHANDLE directoryHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES objectAttributes); namespace NEO { std::unique_ptr ExternalSemaphore::create(OSInterface *osInterface, ExternalSemaphore::Type type, void *handle, int fd) { if (osInterface) { if (osInterface->getDriverModel()->getDriverModelType() == DriverModelType::wddm) { auto externalSemaphore = ExternalSemaphoreWindows::create(osInterface); bool result = externalSemaphore->importSemaphore(handle, fd, 0, nullptr, type, false); if (result == false) { return nullptr; } return externalSemaphore; } } return nullptr; } std::unique_ptr ExternalSemaphoreWindows::create(OSInterface *osInterface) { auto extSemWindows = std::make_unique(); extSemWindows->osInterface = osInterface; extSemWindows->state = SemaphoreState::Initial; return extSemWindows; } bool ExternalSemaphoreWindows::importSemaphore(void *extHandle, int fd, uint32_t flags, const char *name, Type type, bool isNative) { switch (type) { case ExternalSemaphore::D3d12Fence: case ExternalSemaphore::OpaqueWin32: break; default: return false; } HANDLE syncNtHandle = nullptr; this->type = type; auto wddm = this->osInterface->getDriverModel()->as(); syncNtHandle = reinterpret_cast(extHandle); if (type == ExternalSemaphore::OpaqueWin32) { auto moduleHandle = GetModuleHandleA("ntdll.dll"); _RtlInitUnicodeString rtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(moduleHandle, "RtlInitUnicodeString"); _NtOpenDirectoryObject ntOpenDirectoryObject = (_NtOpenDirectoryObject)GetProcAddress(moduleHandle, "NtOpenDirectoryObject"); HANDLE rootDirectory; OBJECT_ATTRIBUTES objectAttributesRootDirectory; UNICODE_STRING unicodeNameRootDirectory; PUNICODE_STRING pUnicodeNameRootDirectory = NULL; wchar_t baseName[] = L"\\BaseNamedObjects"; rtlInitUnicodeString(&unicodeNameRootDirectory, baseName); pUnicodeNameRootDirectory = &unicodeNameRootDirectory; InitializeObjectAttributes(&objectAttributesRootDirectory, pUnicodeNameRootDirectory, 0, nullptr, nullptr); ntOpenDirectoryObject(&rootDirectory, 0x0004 /* DIRECTORY_CREATE_OBJECT */, &objectAttributesRootDirectory); this->pCpuAddress = MapViewOfFile(syncNtHandle, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); auto sharedMemoryContentHeader = this->getSharedMemoryContentHeader(); auto access = sharedMemoryContentHeader->access; auto pSyncName = &sharedMemoryContentHeader->sharedSyncName[0]; this->pLastSignaledValue = &sharedMemoryContentHeader->lastSignaledValue; syncNtHandle = nullptr; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING unicodeName; PUNICODE_STRING pUnicodeName = NULL; const wchar_t *pName = reinterpret_cast(pSyncName); if (pName) { rtlInitUnicodeString(&unicodeName, pName); pUnicodeName = &unicodeName; } InitializeObjectAttributes(&objectAttributes, pUnicodeName, 0, rootDirectory, nullptr); D3DKMT_OPENSYNCOBJECTNTHANDLEFROMNAME openName = {}; openName.dwDesiredAccess = access; openName.pObjAttrib = &objectAttributes; auto status = wddm->getGdi()->openSyncObjectNtHandleFromName(&openName); if (status != STATUS_SUCCESS) { return false; } syncNtHandle = openName.hNtHandle; } D3DKMT_OPENSYNCOBJECTFROMNTHANDLE2 open = {}; open.hNtHandle = syncNtHandle; open.hDevice = wddm->getDeviceHandle(); open.Flags.NoGPUAccess = (type == ExternalSemaphore::D3d12Fence); auto status = wddm->getGdi()->openSyncObjectFromNtHandle2(&open); if (status != STATUS_SUCCESS) { return false; } this->syncHandle = open.hSyncObject; return true; } bool ExternalSemaphoreWindows::enqueueWait(uint64_t *fenceValue) { auto wddm = this->osInterface->getDriverModel()->as(); D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS waitFlags = {}; waitFlags.WaitAny = false; D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU wait = {}; wait.hDevice = wddm->getDeviceHandle(); wait.ObjectCount = 1; wait.ObjectHandleArray = &this->syncHandle; uint64_t lastSignaledValue = 0; if (this->type == ExternalSemaphore::OpaqueWin32) { lastSignaledValue = *this->pLastSignaledValue; wait.FenceValueArray = &lastSignaledValue; } else { wait.FenceValueArray = fenceValue; } wait.FenceValueArray = fenceValue; wait.hAsyncEvent = nullptr; wait.Flags = waitFlags; auto status = wddm->getGdi()->waitForSynchronizationObjectFromCpu(&wait); if (status != STATUS_SUCCESS) { return false; } this->state = SemaphoreState::Signaled; return true; } bool ExternalSemaphoreWindows::enqueueSignal(uint64_t *fenceValue) { auto wddm = this->osInterface->getDriverModel()->as(); D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU signal = {}; signal.hDevice = wddm->getDeviceHandle(); signal.ObjectCount = 1; signal.ObjectHandleArray = &this->syncHandle; uint64_t lastSignaledValue = 0; if (this->type == ExternalSemaphore::OpaqueWin32) { lastSignaledValue = *this->pLastSignaledValue + 2; signal.FenceValueArray = &lastSignaledValue; } else { signal.FenceValueArray = fenceValue; } auto status = wddm->getGdi()->signalSynchronizationObjectFromCpu(&signal); if (status != STATUS_SUCCESS) { return false; } if (this->type == ExternalSemaphore::OpaqueWin32) { *this->pLastSignaledValue += 2; } this->state = SemaphoreState::Signaled; return true; } } // namespace NEO